@godxjp/ui 28.13.0 → 29.0.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/agent/START-HERE.md +29 -10
- package/agent/components/Anchor.json +6 -1
- package/agent/components/AppShell.json +1 -1
- package/agent/components/AreaChart.json +19 -1
- package/agent/components/BarChart.json +11 -1
- package/agent/components/Cascader.json +1 -1
- package/agent/components/CompactBarTrend.json +1 -1
- package/agent/components/DataState.json +1 -1
- package/agent/components/DataTable.json +4 -4
- package/agent/components/FormField.json +1 -1
- package/agent/components/InfiniteQueryState.json +1 -1
- package/agent/components/Input.json +1 -1
- package/agent/components/LineChart.json +20 -2
- package/agent/components/ListRow.json +1 -1
- package/agent/components/Masonry.json +1 -1
- package/agent/components/MasterDetail.json +1 -1
- package/agent/components/PasswordStrength.json +1 -1
- package/agent/components/PermissionMatrix.json +1 -1
- package/agent/components/Select.json +1 -0
- package/agent/components/Sidebar.json +1 -1
- package/agent/components/Table.json +8 -3
- package/agent/components/ThemeScope.json +49 -0
- package/agent/components/Topbar.json +1 -0
- package/agent/components/TopbarItem.json +2 -1
- package/agent/components/Transfer.json +1 -1
- package/agent/components/TreeSelect.json +1 -1
- package/agent/components/UploadCropDialog.json +1 -1
- package/agent/components/formatDate.json +1 -1
- package/agent/components-index.json +5 -0
- package/agent/components.json +138 -30
- package/agent/index.json +19 -9
- package/agent/llms.txt +10 -10
- package/agent/patterns/tenant-brand-color.json +28 -0
- package/agent/patterns-index.json +27 -0
- package/agent/patterns.json +28 -0
- package/agent/rules.json +15 -0
- package/agent/tokens.json +4965 -970
- package/dist/app/index.d.ts +3 -0
- package/dist/app/index.js +3 -0
- package/dist/app/tenant-theme.d.ts +80 -0
- package/dist/app/tenant-theme.js +154 -0
- package/dist/app/theme-axes.d.ts +14 -1
- package/dist/app/theme-axes.js +24 -31
- package/dist/components/charts/chart-cartesian.d.ts +5 -1
- package/dist/components/charts/chart-cartesian.js +15 -8
- package/dist/components/data-display/badge.d.ts +1 -1
- package/dist/components/data-display/badge.js +20 -2
- package/dist/components/data-display/carousel.js +4 -4
- package/dist/components/data-display/data-table.js +13 -2
- package/dist/components/data-display/permission-matrix.js +1 -1
- package/dist/components/data-display/table.d.ts +11 -2
- package/dist/components/data-display/table.js +18 -2
- package/dist/components/data-entry/control-appearance.d.ts +12 -6
- package/dist/components/data-entry/control-appearance.js +1 -1
- package/dist/components/data-entry/select.js +4 -3
- package/dist/components/feedback/dialog.js +6 -3
- package/dist/components/feedback/overlay-header-tone.d.ts +7 -0
- package/dist/components/feedback/overlay-header-tone.js +4 -4
- package/dist/components/feedback/sheet.d.ts +1 -1
- package/dist/components/feedback/sheet.js +6 -9
- package/dist/components/feedback/sonner.js +16 -3
- package/dist/components/general/button.js +22 -5
- package/dist/components/layout/affix.js +15 -1
- package/dist/components/layout/sidebar.js +7 -1
- package/dist/components/navigation/anchor.d.ts +1 -1
- package/dist/components/navigation/anchor.js +5 -4
- package/dist/components/navigation/app-setting-picker.js +1 -1
- package/dist/components/navigation/pagination.js +1 -1
- package/dist/components/navigation/tabs.js +15 -2
- package/dist/components/query/infinite-query-state.d.ts +22 -6
- package/dist/lib/control-styles.d.ts +31 -11
- package/dist/lib/control-styles.js +6 -6
- package/dist/lib/overlay-portal.d.ts +20 -0
- package/dist/lib/overlay-portal.js +93 -0
- package/dist/props/components/app.prop.d.ts +12 -0
- package/dist/props/components/charts.prop.d.ts +30 -0
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/navigation.prop.d.ts +21 -2
- package/dist/props/components/query.prop.d.ts +36 -2
- package/dist/props/registry.d.ts +46 -1
- package/dist/props/registry.js +38 -3
- package/dist/styles/alert-layout.css +34 -14
- package/dist/styles/badge-layout.css +10 -6
- package/dist/styles/base.css +14 -5
- package/dist/styles/card-layout.css +19 -8
- package/dist/styles/chart-layout.css +22 -3
- package/dist/styles/control.css +165 -59
- package/dist/styles/data-display-layout.css +129 -36
- package/dist/styles/data-entry-layout.css +23 -87
- package/dist/styles/dialog-layout.css +49 -19
- package/dist/styles/float-button-layout.css +5 -5
- package/dist/styles/focus-ring.css +9 -5
- package/dist/styles/layout.css +42 -15
- package/dist/styles/logo-layout.css +1 -1
- package/dist/styles/motion.css +1 -1
- package/dist/styles/navigation-layout.css +90 -29
- package/dist/styles/shell-layout.css +63 -40
- package/dist/styles/table-layout.css +56 -17
- package/dist/styles/text-layout.css +13 -4
- package/dist/styles/toggle.css +8 -2
- package/dist/tokens/components/actions.css +1 -1
- package/dist/tokens/components/attachments.css +4 -4
- package/dist/tokens/components/badge.css +4 -4
- package/dist/tokens/components/callout.css +1 -1
- package/dist/tokens/components/card.css +9 -4
- package/dist/tokens/components/chart.css +10 -1
- package/dist/tokens/components/chat-bubble.css +1 -1
- package/dist/tokens/components/control.css +28 -10
- package/dist/tokens/components/conversations.css +2 -1
- package/dist/tokens/components/data-display.css +12 -7
- package/dist/tokens/components/descriptions.css +1 -1
- package/dist/tokens/components/draggable-panel.css +1 -1
- package/dist/tokens/components/feedback.css +28 -8
- package/dist/tokens/components/float-button.css +1 -1
- package/dist/tokens/components/legal-document.css +1 -1
- package/dist/tokens/components/logo.css +1 -1
- package/dist/tokens/components/mega-menu.css +5 -3
- package/dist/tokens/components/navigation.css +21 -7
- package/dist/tokens/components/segmented.css +8 -3
- package/dist/tokens/components/shell.css +19 -5
- package/dist/tokens/components/table.css +9 -1
- package/dist/tokens/components/thought-chain.css +1 -1
- package/dist/tokens/components/toggle.css +2 -0
- package/dist/tokens/components/tree.css +3 -1
- package/dist/tokens/components/upload.css +6 -6
- package/dist/tokens/components/welcome.css +1 -1
- package/dist/tokens/foundation.css +28 -1
- package/docs/COMPOSITION-VS-COMPONENT.md +31 -0
- package/docs/CUSTOMER-THEMING.md +637 -1
- package/docs/FRAME-COVERAGE-REPORT.md +3 -2
- package/docs/GLASSMORPHISM-STANDARD.md +196 -0
- package/docs/THEME-API-COVERAGE.md +538 -0
- package/docs/TOKEN-RESOLUTION.md +195 -0
- package/docs/TOKENS.md +63 -24
- package/docs/asset-modules.d.ts +7 -0
- package/docs/data-display/charts.tsx +80 -0
- package/docs/data-display/data-table/index.tsx +30 -0
- package/docs/data-display/popover.tsx +1 -1
- package/docs/data-display/table.tsx +52 -0
- package/docs/feedback/sheet.tsx +10 -10
- package/docs/foundation/density.tsx +4 -4
- package/docs/i18n/messages/en.json +502 -0
- package/docs/i18n/messages/ja.json +502 -0
- package/docs/i18n/messages/vi.json +502 -0
- package/docs/layout/account-chip.tsx +2 -2
- package/docs/layout/responsive-grid.tsx +1 -1
- package/docs/navigation/toolbar.tsx +20 -12
- package/docs/providers/theme-scope.tsx +186 -0
- package/docs/showcase/caimono-price-comparison.tsx +911 -0
- package/docs/showcase/case4-login.tsx +2 -2
- package/docs/showcase/permission-matrix.tsx +13 -5
- package/docs/showcase/table-pagination.tsx +2 -1
- package/docs/showcase/tenant-brand-color.tsx +338 -0
- package/docs/showcase/theme-lab.tsx +2125 -0
- package/docs/themes/flat.css +462 -0
- package/docs/themes/glassmorphism.css +958 -0
- package/docs/themes/index.ts +200 -0
- package/package.json +4 -3
- package/scripts/explain-token.mjs +382 -0
|
@@ -78,14 +78,30 @@ const TableBody = React.forwardRef(({ className, ...props }, ref) => (
|
|
|
78
78
|
/* @__PURE__ */ jsx("tbody", { ref, "data-slot": "table-body", className: cn(className), ...props })
|
|
79
79
|
));
|
|
80
80
|
TableBody.displayName = "TableBody";
|
|
81
|
-
const TableRow = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
81
|
+
const TableRow = React.forwardRef(({ className, tone, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
82
82
|
"tr",
|
|
83
83
|
{
|
|
84
84
|
ref,
|
|
85
|
+
"data-tone": tone,
|
|
85
86
|
className: cn(
|
|
86
87
|
// The row rule itself is `.ui-table-row` in table-layout.css (--table-row-border-width),
|
|
87
88
|
// NOT a `border-b` utility — a utility sits in `@layer utilities` and would outrank the
|
|
88
|
-
|
|
89
|
+
//
|
|
90
|
+
// THE WASH NOW READS THE SAME TOKEN THE PINNED-COLUMN MIRROR ALREADY DID (gh#894). A bare
|
|
91
|
+
// `hover:bg-accent/70` could not be retuned by any theme — the pin-column mirror right
|
|
92
|
+
// below this file's own selectors (table-layout.css, data-display-layout.css) already
|
|
93
|
+
// reads `--table-row-hover-background-alpha`, so the row that actually owns the fill was
|
|
94
|
+
// the one piece a theme could not reach. The shared default stays 0.7 (unchanged; gh#700
|
|
95
|
+
// needs it >= ~0.68 or a striped row's hover stops being a visible step) — a tone Badge
|
|
96
|
+
// composed over a hovered GLASS row still measures 4.02–4.34:1 on four of five seeds, and
|
|
97
|
+
// clearing that needs glass's OWN lower value for this token (its theme file, not this
|
|
98
|
+
// one). What this line fixes is that a theme now CAN set that value at all.
|
|
99
|
+
//
|
|
100
|
+
// `color-mix(…)`, not `hsl(var(--accent) / var(--x, 70%))`: Tailwind's arbitrary-property
|
|
101
|
+
// parser treats a bare `/` inside the bracket as ITS OWN opacity-modifier boundary — that
|
|
102
|
+
// spelling measured 0.1 alpha in Chromium (not 0.7), silently. `color-mix` has no `/` for
|
|
103
|
+
// it to misread, matching the same idiom `toneSuccessClass` already uses (control-styles.ts).
|
|
104
|
+
"ui-table-row data-[state=selected]:bg-primary/[0.06] transition-colors hover:[background-color:color-mix(in_oklab,hsl(var(--accent))_var(--table-row-hover-background-alpha,70%),transparent)]",
|
|
89
105
|
className
|
|
90
106
|
),
|
|
91
107
|
...props
|
|
@@ -28,13 +28,19 @@ export type ControlAppearanceAttributes = {
|
|
|
28
28
|
*/
|
|
29
29
|
export declare function controlAppearanceAttributes({ status, variant, "aria-invalid": ariaInvalid, }: ControlAppearanceInput): ControlAppearanceAttributes;
|
|
30
30
|
/**
|
|
31
|
-
* The chrome
|
|
31
|
+
* The chrome a variant carries, kept in the COMPONENT rather than in `control.css`.
|
|
32
32
|
*
|
|
33
|
-
* A Tailwind utility lives in `@layer utilities`, which outranks `@layer components` no matter
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
33
|
+
* A Tailwind utility lives in `@layer utilities`, which outranks `@layer components` no matter how
|
|
34
|
+
* specific the component rule is — so a chrome class baked unconditionally into the base list
|
|
35
|
+
* would silently defeat `filled` and `borderless` and no gate would notice. Each variant therefore
|
|
36
|
+
* receives exactly its own, and the other two never see it.
|
|
37
|
+
*
|
|
38
|
+
* `outlined` USED TO BE THE TWO UTILITIES `border-input bg-background` (gh#880). That is why
|
|
39
|
+
* `--control-surface-background` / `--control-surface-border-color` — documented, published, and
|
|
40
|
+
* reaching the whole select family through `.ui-control-surface` — reached neither Input nor
|
|
41
|
+
* DatePicker: the utilities outranked the tokens by construction. It is a component CLASS now, so
|
|
42
|
+
* the same two tokens paint every field in the library. No token was added; the existing pair just
|
|
43
|
+
* has no hole left in it. See `.ui-control-outlined-surface` in control.css.
|
|
38
44
|
*/
|
|
39
45
|
export declare const CONTROL_VARIANT_CHROME_CLASS: Record<ControlVariantProp, string>;
|
|
40
46
|
/**
|
|
@@ -213,6 +213,7 @@ function LabelInValueSelect({
|
|
|
213
213
|
}
|
|
214
214
|
function CompoundSelect({ id, name, ...props }) {
|
|
215
215
|
const fieldA11y = pickFieldA11y(props);
|
|
216
|
+
const nameFallback = useFieldNameFallback(fieldA11y);
|
|
216
217
|
const identity = useFieldIdentity({ id, name, "data-field": fieldA11y["data-field"] });
|
|
217
218
|
return /* @__PURE__ */ jsx(
|
|
218
219
|
SelectFieldA11yContext.Provider,
|
|
@@ -229,7 +230,7 @@ function CompoundSelect({ id, name, ...props }) {
|
|
|
229
230
|
id,
|
|
230
231
|
name: name ?? identity.name,
|
|
231
232
|
"aria-label": fieldA11y["aria-label"],
|
|
232
|
-
"aria-labelledby": fieldA11y["aria-labelledby"]
|
|
233
|
+
"aria-labelledby": fieldA11y["aria-labelledby"] ?? nameFallback["aria-labelledby"]
|
|
233
234
|
}
|
|
234
235
|
)
|
|
235
236
|
}
|
|
@@ -731,8 +732,8 @@ function DataSelect(props) {
|
|
|
731
732
|
},
|
|
732
733
|
disabled: disabled || !hasOptions && !showEmptyPopup,
|
|
733
734
|
allowsEmptyCollection: showEmptyPopup,
|
|
734
|
-
"aria-label": ariaProps["aria-label"],
|
|
735
|
-
"aria-labelledby": ariaProps["aria-labelledby"],
|
|
735
|
+
"aria-label": ariaProps["aria-label"] ?? nameFromPlaceholder,
|
|
736
|
+
"aria-labelledby": ariaProps["aria-labelledby"] ?? inheritedName["aria-labelledby"],
|
|
736
737
|
name: resolvedName,
|
|
737
738
|
open,
|
|
738
739
|
defaultOpen,
|
|
@@ -93,7 +93,10 @@ function DialogShell({
|
|
|
93
93
|
...props,
|
|
94
94
|
style,
|
|
95
95
|
ref: mergeRefs(ref, racRef, contentRef),
|
|
96
|
-
onKeyDown: chain(
|
|
96
|
+
onKeyDown: chain(
|
|
97
|
+
props.onKeyDown,
|
|
98
|
+
closeOnEscape(() => state.setOpen(false))
|
|
99
|
+
)
|
|
97
100
|
}
|
|
98
101
|
);
|
|
99
102
|
},
|
|
@@ -195,7 +198,7 @@ function DialogContent({
|
|
|
195
198
|
showCloseButton ? /* @__PURE__ */ jsxs(
|
|
196
199
|
DialogClose,
|
|
197
200
|
{
|
|
198
|
-
className: "ui-focus-ring transition-opacity disabled:pointer-events-none",
|
|
201
|
+
className: "ui-dialog-close ui-focus-ring transition-opacity disabled:pointer-events-none",
|
|
199
202
|
children: [
|
|
200
203
|
/* @__PURE__ */ jsx(X, { className: "ui-dialog-close-icon", "aria-hidden": "true" }),
|
|
201
204
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: t("feedback.alert.dismiss") })
|
|
@@ -313,7 +316,7 @@ function AlertDialogContent({
|
|
|
313
316
|
{
|
|
314
317
|
type: "button",
|
|
315
318
|
"data-slot": "dialog-close",
|
|
316
|
-
className: "ui-focus-ring transition-opacity disabled:pointer-events-none",
|
|
319
|
+
className: "ui-dialog-close ui-focus-ring transition-opacity disabled:pointer-events-none",
|
|
317
320
|
"aria-label": t("feedback.alert.dismiss"),
|
|
318
321
|
onClick: () => {
|
|
319
322
|
state.setOpen(false);
|
|
@@ -3,5 +3,12 @@ import type { ToneProp } from "../../props/vocabulary/index.js";
|
|
|
3
3
|
* Soft semantic background band for an overlay header (Sheet / Dialog / Drawer).
|
|
4
4
|
* Tints ONLY the background — text stays `--foreground` (渋み: never invert the band into a loud
|
|
5
5
|
* solid fill).
|
|
6
|
+
*
|
|
7
|
+
* The four STATUS bands read `--surface-*` with today's 10% wash as the call-site fallback
|
|
8
|
+
* (gh#866), so a brand whose kit pairs each status ink with an independently chosen pale ground
|
|
9
|
+
* paints that ground here too — the band is one of eight surfaces that used to derive its own and
|
|
10
|
+
* therefore could not agree with the Badge sitting in it. `muted`/`neutral` are not statuses and
|
|
11
|
+
* keep `bg-muted`. Arbitrary property rather than `bg-success/10`: same utility layer, same
|
|
12
|
+
* specificity, nothing about the cascade moves.
|
|
6
13
|
*/
|
|
7
14
|
export declare const overlayHeaderToneClass: Record<ToneProp, string>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const overlayHeaderToneClass = {
|
|
2
2
|
default: "",
|
|
3
|
-
success: "
|
|
4
|
-
warning: "
|
|
5
|
-
destructive: "
|
|
6
|
-
info: "
|
|
3
|
+
success: "[background-color:var(--surface-success,color-mix(in_oklab,hsl(var(--success))_10%,transparent))]",
|
|
4
|
+
warning: "[background-color:var(--surface-warning,color-mix(in_oklab,hsl(var(--warning))_10%,transparent))]",
|
|
5
|
+
destructive: "[background-color:var(--surface-destructive,color-mix(in_oklab,hsl(var(--destructive))_10%,transparent))]",
|
|
6
|
+
info: "[background-color:var(--surface-info,color-mix(in_oklab,hsl(var(--info))_10%,transparent))]",
|
|
7
7
|
muted: "bg-muted",
|
|
8
8
|
neutral: "bg-muted"
|
|
9
9
|
};
|
|
@@ -28,7 +28,7 @@ export interface SheetProps {
|
|
|
28
28
|
modal?: boolean;
|
|
29
29
|
children?: React.ReactNode;
|
|
30
30
|
}
|
|
31
|
-
export declare function Sheet({ open, defaultOpen, onOpenChange, modal, children
|
|
31
|
+
export declare function Sheet({ open, defaultOpen, onOpenChange, modal, children }: SheetProps): React.JSX.Element;
|
|
32
32
|
export interface SheetTriggerProps extends React.ComponentPropsWithRef<"button"> {
|
|
33
33
|
/** Mượn thẻ của con thay vì dựng `<button>` riêng. */
|
|
34
34
|
asChild?: boolean;
|
|
@@ -31,13 +31,7 @@ function useSheetOpenState(component) {
|
|
|
31
31
|
}
|
|
32
32
|
const SheetModalContext = React.createContext(true);
|
|
33
33
|
const SheetLabelContext = React.createContext(null);
|
|
34
|
-
function Sheet({
|
|
35
|
-
open,
|
|
36
|
-
defaultOpen,
|
|
37
|
-
onOpenChange,
|
|
38
|
-
modal = true,
|
|
39
|
-
children
|
|
40
|
-
}) {
|
|
34
|
+
function Sheet({ open, defaultOpen, onOpenChange, modal = true, children }) {
|
|
41
35
|
const [uncontrolled, setUncontrolled] = React.useState(defaultOpen ?? false);
|
|
42
36
|
const isOpen = open ?? uncontrolled;
|
|
43
37
|
const setOpen = React.useCallback(
|
|
@@ -97,7 +91,7 @@ function SheetOverlay(_props) {
|
|
|
97
91
|
SheetOverlay.displayName = "SheetOverlay";
|
|
98
92
|
const SHEET_OVERLAY_CLASS = "ui-sheet-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 fixed";
|
|
99
93
|
const sheetVariants = cva(
|
|
100
|
-
"ui-sheet-panel fixed flex flex-col gap-[var(--space-chrome-gap)]
|
|
94
|
+
"ui-sheet-panel fixed flex flex-col gap-[var(--space-chrome-gap)] text-foreground px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)] transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
|
|
101
95
|
{
|
|
102
96
|
variants: {
|
|
103
97
|
// `side` is a deliberately PHYSICAL API (left/right/top/bottom) — a sheet
|
|
@@ -171,7 +165,10 @@ function SheetContent({
|
|
|
171
165
|
...props,
|
|
172
166
|
style: mergedStyle,
|
|
173
167
|
ref: mergeRefs(ref, racRef, contentRef),
|
|
174
|
-
onKeyDown: chain(
|
|
168
|
+
onKeyDown: chain(
|
|
169
|
+
props.onKeyDown,
|
|
170
|
+
closeOnEscape(() => state.setOpen(false))
|
|
171
|
+
)
|
|
175
172
|
}
|
|
176
173
|
);
|
|
177
174
|
},
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
4
5
|
import { CheckCircle2, Info, Loader2, OctagonX, TriangleAlert } from "lucide-react";
|
|
5
6
|
import { Toaster as Sonner } from "sonner";
|
|
7
|
+
import { useOverlayPortalContainer } from "../../lib/overlay-portal.js";
|
|
6
8
|
function useDocumentTheme() {
|
|
7
9
|
return React.useSyncExternalStore(
|
|
8
10
|
(onStoreChange) => {
|
|
@@ -33,7 +35,11 @@ const toneVars = Object.fromEntries(
|
|
|
33
35
|
TOAST_TONES.flatMap(({ type, hue, ink }) => [
|
|
34
36
|
[
|
|
35
37
|
`--${type}-bg`,
|
|
36
|
-
|
|
38
|
+
// gh#866 — the surface reads its `--surface-*` role first, with the composite above as the
|
|
39
|
+
// call-site fallback. Without it the toast was the fourth of eight status surfaces that
|
|
40
|
+
// could only ever be a derivation of its own ink, so a brand's chosen pale ground reached
|
|
41
|
+
// the Alert and not the toast that says the same sentence.
|
|
42
|
+
`var(--surface-${hue}, color-mix(in srgb, hsl(var(--${hue})) calc(var(--alert-bg-alpha) * 100%), hsl(var(--popover) / var(--popover-alpha, 100%))))`
|
|
37
43
|
],
|
|
38
44
|
[`--${type}-border`, `hsl(var(--${hue}) / var(--alert-border-alpha))`],
|
|
39
45
|
[`--${type}-text`, `hsl(var(--${ink}))`]
|
|
@@ -41,7 +47,8 @@ const toneVars = Object.fromEntries(
|
|
|
41
47
|
);
|
|
42
48
|
function Toaster({ style, richColors = true, ...props }) {
|
|
43
49
|
const theme = useDocumentTheme();
|
|
44
|
-
|
|
50
|
+
const overlayPortalContainer = useOverlayPortalContainer();
|
|
51
|
+
const toaster = /* @__PURE__ */ jsx(
|
|
45
52
|
Sonner,
|
|
46
53
|
{
|
|
47
54
|
theme,
|
|
@@ -59,7 +66,12 @@ function Toaster({ style, richColors = true, ...props }) {
|
|
|
59
66
|
// sonner uses these vars verbatim as CSS colors, so wrap with hsl()
|
|
60
67
|
// here — unwrapped they are invalid values and the toast renders
|
|
61
68
|
// transparent.
|
|
62
|
-
|
|
69
|
+
// `--normal-bg` is SONNER's private name, so the package's own knob is threaded through
|
|
70
|
+
// it (gh#880): a theme sets `--toast-background` like every other surface's fill and
|
|
71
|
+
// never has to know that this one surface is painted by a vendor stylesheet. The default
|
|
72
|
+
// is the same `hsl(var(--popover))` and resolves in the browser, on the toaster, under
|
|
73
|
+
// whatever scope it sits in — so a themed region's toast follows the region (gh#877).
|
|
74
|
+
"--normal-bg": "var(--toast-background, hsl(var(--popover) / var(--popover-alpha, 100%)))",
|
|
63
75
|
"--normal-text": "hsl(var(--popover-foreground))",
|
|
64
76
|
"--normal-border": "hsl(var(--border))",
|
|
65
77
|
"--border-radius": "var(--radius)",
|
|
@@ -77,6 +89,7 @@ function Toaster({ style, richColors = true, ...props }) {
|
|
|
77
89
|
...props
|
|
78
90
|
}
|
|
79
91
|
);
|
|
92
|
+
return overlayPortalContainer ? createPortal(toaster, overlayPortalContainer) : toaster;
|
|
80
93
|
}
|
|
81
94
|
export {
|
|
82
95
|
Toaster
|
|
@@ -16,17 +16,34 @@ const buttonVariants = cva("ui-button", {
|
|
|
16
16
|
// utilities, out-ranked it: the hover step this library takes from the derived tier
|
|
17
17
|
// (`--primary-hover`) could never take effect while `hover:bg-primary/90` was emitted here.
|
|
18
18
|
default: "ui-button--default",
|
|
19
|
-
|
|
19
|
+
// `bg-destructive` LEFT for the reason spelled out on `default` above, and gh#880 is
|
|
20
|
+
// where it finally cost something: a utility out-ranks `@layer components`, so
|
|
21
|
+
// `--button-destructive-background` could not have reached this variant while it stood.
|
|
22
|
+
// The ink stays a utility — nothing competes for `color` here.
|
|
23
|
+
destructive: "ui-button--destructive text-destructive-foreground",
|
|
20
24
|
// `shadow-xs` từng nằm ở đây và mắc ĐÚNG lỗi đã nêu ngay trên cho `default`:
|
|
21
25
|
// một utility thì out-rank tầng components, nên bóng của nút outline đi vòng
|
|
22
26
|
// qua tầng token — consumer đặt `--shadow-sm: none` thì `default` sạch bóng còn
|
|
23
27
|
// `outline` trơ ra. Nay bóng khai ở `.ui-button--outline` và đọc `var(--shadow-sm)`
|
|
24
28
|
// như mọi biến thể khác, nên nó tắt/đổi được qua theme. (gh#662)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
// `bg-background` gone for the same reason (gh#880). The HOVER fill stays a utility: it
|
|
30
|
+
// is the same value `.ui-button--outline:hover` declares, and moving it is a separate
|
|
31
|
+
// decision from making the resting surface reachable.
|
|
32
|
+
outline: "ui-button--outline border hover:bg-accent hover:text-accent-foreground",
|
|
33
|
+
// `dashed` is `outline` with a dashed edge, so it shares `--button-outline-background`
|
|
34
|
+
// rather than growing a knob of its own (gh#880).
|
|
35
|
+
dashed: "ui-button--dashed border border-dashed hover:bg-accent hover:text-accent-foreground",
|
|
36
|
+
secondary: "ui-button--secondary text-secondary-foreground hover:bg-secondary/80",
|
|
28
37
|
ghost: "ui-button--ghost hover:bg-accent hover:text-accent-foreground",
|
|
29
|
-
|
|
38
|
+
// `text-primary` gone for the reason `bg-background` went in gh#880 and the checkbox's
|
|
39
|
+
// `data-[state=checked]:bg-primary` went before it: a utility is layered AFTER components in
|
|
40
|
+
// Tailwind v4, so it silently out-ranked `.ui-button--link`'s own `color` and NO token could
|
|
41
|
+
// reach this ink. gh#884 measured the consequence — the link is the one Button variant whose
|
|
42
|
+
// brand colour is TEXT on a page surface rather than a fill, and it fails WCAG 2.2 AA at
|
|
43
|
+
// 9 of 15 theme x seed cells. The components-layer rule now resolves
|
|
44
|
+
// `var(--button-link-foreground, hsl(var(--primary)))`, and `text-primary` compiled to
|
|
45
|
+
// exactly that fallback, so the default is byte-identical.
|
|
46
|
+
link: "ui-button--link underline-offset-4 hover:underline",
|
|
30
47
|
// NO utilities, deliberately: `bare` is the absence of geometry, and every property it has
|
|
31
48
|
// to unset (the size tier's height and inline inset) is declared in the components layer.
|
|
32
49
|
// A utility here would be the only thing that could out-rank it. See `.ui-button--bare`.
|
|
@@ -13,6 +13,16 @@ function resolveTarget(target) {
|
|
|
13
13
|
if (!node || typeof window === "undefined" || node === window) return null;
|
|
14
14
|
return node;
|
|
15
15
|
}
|
|
16
|
+
function fixedContainingBlock(node) {
|
|
17
|
+
if (typeof window === "undefined") return null;
|
|
18
|
+
for (let n = node?.parentElement ?? null; n && n !== document.documentElement; n = n.parentElement) {
|
|
19
|
+
const cs = window.getComputedStyle(n);
|
|
20
|
+
if (cs.filter !== "none" || cs.backdropFilter !== "none" || cs.transform !== "none" || cs.perspective !== "none" || /transform|filter|perspective/.test(cs.willChange) || /paint|layout|strict|content/.test(cs.contain)) {
|
|
21
|
+
return n;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
16
26
|
const Affix = React.forwardRef(function Affix2({
|
|
17
27
|
children,
|
|
18
28
|
offsetBlockStart,
|
|
@@ -63,7 +73,11 @@ const Affix = React.forwardRef(function Affix2({
|
|
|
63
73
|
(previous) => previous && previous.inline === rootRect.width && previous.block === contentRect.height ? previous : { inline: rootRect.width, block: contentRect.height }
|
|
64
74
|
);
|
|
65
75
|
const rect = targetElement?.getBoundingClientRect();
|
|
66
|
-
const
|
|
76
|
+
const blockEl = fixedContainingBlock(content);
|
|
77
|
+
const block = blockEl?.getBoundingClientRect();
|
|
78
|
+
const viewportInset = rect ? pinToEnd ? window.innerHeight - rect.bottom : rect.top : 0;
|
|
79
|
+
const blockOffset = block ? pinToEnd ? window.innerHeight - (block.bottom + ((blockEl?.scrollHeight ?? 0) - (blockEl?.clientHeight ?? 0) - (blockEl?.scrollTop ?? 0))) : block.top - (blockEl?.scrollTop ?? 0) : 0;
|
|
80
|
+
const next = viewportInset - blockOffset;
|
|
67
81
|
setTargetInset((previous) => previous === next ? previous : next);
|
|
68
82
|
}, [pinToEnd, targetElement]);
|
|
69
83
|
React.useLayoutEffect(() => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { CONTRAST_PIVOT, relativeLuminance } from "../../app/tenant-theme.js";
|
|
4
5
|
import { Slot } from "../../lib/slot.js";
|
|
5
6
|
import { ChevronDown } from "lucide-react";
|
|
6
7
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../data-display/collapsible.js";
|
|
@@ -315,11 +316,16 @@ function Sidebar({
|
|
|
315
316
|
return /* @__PURE__ */ jsxs("div", { className: "sb-root", "data-collapsed": collapsed ? "true" : void 0, children: [
|
|
316
317
|
brand !== void 0 ? /* @__PURE__ */ jsx(SidebarHeader, { children: brandNode }) : product ? (() => {
|
|
317
318
|
const interactive = onProductClick != null;
|
|
319
|
+
const markLuminance = product.color != null ? relativeLuminance(product.color) : null;
|
|
320
|
+
const markInk = product.color == null ? "hsl(var(--attention-foreground))" : markLuminance == null ? "white" : markLuminance > CONTRAST_PIVOT ? "black" : "white";
|
|
318
321
|
const mark = /* @__PURE__ */ jsx(
|
|
319
322
|
"span",
|
|
320
323
|
{
|
|
321
324
|
className: "sb-logo-mark",
|
|
322
|
-
style: {
|
|
325
|
+
style: {
|
|
326
|
+
background: product.color ?? "hsl(var(--attention))",
|
|
327
|
+
color: `var(--sidebar-logo-mark-color, ${markInk})`
|
|
328
|
+
},
|
|
323
329
|
children: product.name[0]?.toUpperCase() ?? "?"
|
|
324
330
|
}
|
|
325
331
|
);
|
|
@@ -58,7 +58,7 @@ export type { AnchorContainerProp, AnchorDirectionProp, AnchorItemProp, AnchorPr
|
|
|
58
58
|
* the target section, not just the scroll position, so the next Tab continues from where the
|
|
59
59
|
* reader was sent instead of from the nav.
|
|
60
60
|
*/
|
|
61
|
-
export declare function Anchor({ items, direction, affix, bounds, getContainer, getCurrentAnchor, offsetBlockStart, targetOffsetBlockStart, showInkInFixed, replace, value, defaultValue, onValueChange, onChange, offsetTop, targetOffset, onClick, label, id, className, ...rest }: AnchorProp): React.JSX.Element;
|
|
61
|
+
export declare function Anchor({ items, direction, affix, bounds, target, getContainer, getCurrentAnchor, offsetBlockStart, targetOffsetBlockStart, showInkInFixed, replace, value, defaultValue, onValueChange, onChange, offsetTop, targetOffset, onClick, label, id, className, ...rest }: AnchorProp): React.JSX.Element;
|
|
62
62
|
export declare namespace Anchor {
|
|
63
63
|
var displayName: string;
|
|
64
64
|
}
|
|
@@ -36,6 +36,7 @@ function Anchor({
|
|
|
36
36
|
direction = "vertical",
|
|
37
37
|
affix = true,
|
|
38
38
|
bounds = DEFAULT_BOUNDS,
|
|
39
|
+
target,
|
|
39
40
|
getContainer,
|
|
40
41
|
getCurrentAnchor,
|
|
41
42
|
offsetBlockStart,
|
|
@@ -117,10 +118,10 @@ function Anchor({
|
|
|
117
118
|
if (!controlledRef.current) setInternal(href);
|
|
118
119
|
onValueChangeRef.current?.(href);
|
|
119
120
|
}, []);
|
|
120
|
-
const container = React.useCallback(
|
|
121
|
-
()
|
|
122
|
-
|
|
123
|
-
);
|
|
121
|
+
const container = React.useCallback(() => {
|
|
122
|
+
if (target) return target() ?? window;
|
|
123
|
+
return getContainer?.() ?? window;
|
|
124
|
+
}, [target, getContainer]);
|
|
124
125
|
const line = targetOffsetBlockStart ?? offsetBlockStart ?? 0;
|
|
125
126
|
const resolveFromScroll = React.useCallback(() => {
|
|
126
127
|
if (typeof document === "undefined") return "";
|
|
@@ -122,6 +122,7 @@ const AppSettingPicker = React.forwardRef(
|
|
|
122
122
|
}),
|
|
123
123
|
disabled: disabled || unbound,
|
|
124
124
|
name,
|
|
125
|
+
"aria-label": t(ARIA_KEY[kind]),
|
|
125
126
|
children: [
|
|
126
127
|
/* @__PURE__ */ jsxs(
|
|
127
128
|
SelectTrigger,
|
|
@@ -216,7 +217,6 @@ const AppSettingPicker = React.forwardRef(
|
|
|
216
217
|
),
|
|
217
218
|
"data-kind": kind,
|
|
218
219
|
"data-appearance": resolvedAppearance,
|
|
219
|
-
"aria-label": t(ARIA_KEY[kind]),
|
|
220
220
|
children: [
|
|
221
221
|
inline ? null : /* @__PURE__ */ jsx(
|
|
222
222
|
Icon,
|
|
@@ -241,12 +241,12 @@ function Pagination({
|
|
|
241
241
|
value: String(pageSize),
|
|
242
242
|
onValueChange: (v) => go(1, Number(v)),
|
|
243
243
|
disabled,
|
|
244
|
+
"aria-label": t("navigation.pagination.pageSize"),
|
|
244
245
|
children: [
|
|
245
246
|
/* @__PURE__ */ jsx(
|
|
246
247
|
SelectTrigger,
|
|
247
248
|
{
|
|
248
249
|
className: "ui-pagination-size-trigger w-max min-w-[var(--pagination-size-width)]",
|
|
249
|
-
"aria-label": t("navigation.pagination.pageSize"),
|
|
250
250
|
children: /* @__PURE__ */ jsx(SelectValue, { children: t("navigation.pagination.pageSizeTrigger", { size: pageSize }) })
|
|
251
251
|
}
|
|
252
252
|
),
|
|
@@ -494,7 +494,14 @@ const TabsList = React.forwardRef(
|
|
|
494
494
|
// — so the leading tab sat permanently outside the scrollport (an unreachable control at
|
|
495
495
|
// 320px, WCAG 2.2 SC 2.1.1). `safe` falls back to start alignment exactly when it
|
|
496
496
|
// overflows, and still centres whenever the tabs fit.
|
|
497
|
-
|
|
497
|
+
// `data-[variant=default]:bg-muted` USED TO BE HERE AND IS NOW `--tabs-list-background`
|
|
498
|
+
// in navigation-layout.css (gh#880). A Tailwind utility lives in `@layer utilities`, so
|
|
499
|
+
// while the track was painted from here NO rule this package writes could reach it and a
|
|
500
|
+
// theme had no knob at all — the visible defect being a translucent Card whose Tabs strip
|
|
501
|
+
// stayed opaque `--muted`. Nothing about the card/line strips changes: both clear the
|
|
502
|
+
// track with utilities of their own (`data-[variant=default]:bg-transparent`,
|
|
503
|
+
// `data-[variant=line]:bg-transparent`), and a utility still outranks the new rule.
|
|
504
|
+
"group/tabs-list text-muted-foreground inline-flex w-fit max-w-full min-w-0 items-center justify-center-safe rounded-lg p-1 group-data-[orientation=vertical]/tabs:flex-col data-[orientation=horizontal]:[scrollbar-width:none] data-[orientation=horizontal]:overflow-x-auto data-[orientation=horizontal]:overflow-y-hidden data-[variant=line]:gap-[var(--tabs-list-line-space-gap)] data-[variant=line]:rounded-none data-[variant=line]:bg-transparent [&[data-orientation=horizontal]::-webkit-scrollbar]:hidden",
|
|
498
505
|
className
|
|
499
506
|
),
|
|
500
507
|
render: (domProps) => withDomProps("div", "tabs-list", props, domProps, { "data-variant": variant }),
|
|
@@ -541,7 +548,13 @@ const TabsTrigger = React.forwardRef(
|
|
|
541
548
|
// labels needing 107 / 95 / 53px, i.e. the SAME defect one API away. antd puts no
|
|
542
549
|
// `flex-grow` on a tab of any `type`, so the rule belongs to the line STRIP rather than
|
|
543
550
|
// to one construction path; the pill strip keeps `flex-1`, which is what fills its box.
|
|
544
|
-
|
|
551
|
+
// `data-[state=active]:bg-background` USED TO BE HERE and is now
|
|
552
|
+
// `--tabs-trigger-active-background` in navigation-layout.css, for the same reason as the
|
|
553
|
+
// list's track (gh#880): the selected slab of this library's other track-and-slab control
|
|
554
|
+
// — Segmented — has been `--segmented-item-selected-background` since gh#848, and these
|
|
555
|
+
// two are documented as the same pair. The card face and the line strip both restate the
|
|
556
|
+
// fill as utilities, which still outrank the new rule, so neither moves.
|
|
557
|
+
"text-muted-foreground ring-offset-background hover:text-foreground ui-focus-ring data-[state=active]:text-foreground group-data-[variant=default]/tabs:group-data-[variant=default]/tabs-list:data-[state=active]:border-primary/25 relative inline-flex flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-3 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:flex-none group-data-[orientation=vertical]/tabs:justify-start group-data-[variant=line]/tabs-list:flex-none group-data-[variant=line]/tabs-list:border-e-0 group-data-[variant=line]/tabs-list:border-b-0 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs:group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none",
|
|
545
558
|
// The tier the root was given. Without this the compound form ignored `size` outright.
|
|
546
559
|
triggerSizeClassName(size),
|
|
547
560
|
className
|
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { InfiniteQueryStateProp } from "../../props/components/query.prop.js";
|
|
3
3
|
export type { InfiniteQueryStateProp, InfiniteQueryStateProp as InfiniteQueryStateProps, } from "../../props/components/query.prop.js";
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Flatten `{ pages: [{ items }] }` — default GODX paginated API shape.
|
|
6
|
+
*
|
|
7
|
+
* TItem USED TO BE ITS OWN TYPE PARAMETER, constrained by `TPage extends { items: TItem[] }`, and
|
|
8
|
+
* that made it uninferable in the one way this function is documented to be used. TypeScript infers
|
|
9
|
+
* a type parameter from ARGUMENT POSITIONS, never from another parameter's constraint, so passing
|
|
10
|
+
* the function by reference — `flatten={flattenItemPages}`, the whole API — left TItem at its
|
|
11
|
+
* fallback and collapsed InfiniteQueryState's TFlat to `unknown`. The catalog example was written
|
|
12
|
+
* with `flattenItemPages as any` and `(items: any)` to silence exactly that, which is how the
|
|
13
|
+
* signature survived (gh#889).
|
|
14
|
+
*
|
|
15
|
+
* Taking the page shape INLINE — `{ pages: { items: TItem[] }[] }` — puts TItem in an argument
|
|
16
|
+
* position, so it is inferred from the real page type and `items` arrives as `Activity[]`. TPage
|
|
17
|
+
* itself was never used for anything but that constraint, so naming it bought nothing.
|
|
18
|
+
*/
|
|
19
|
+
export declare function flattenItemPages<TItem>(data: {
|
|
20
|
+
pages: {
|
|
21
|
+
items: TItem[];
|
|
22
|
+
}[];
|
|
9
23
|
} | undefined): TItem[];
|
|
10
24
|
/**
|
|
11
25
|
* `useInfiniteQuery` lifecycle widget — flatten pages, load-more footer.
|
|
12
26
|
* Cursor / activity feeds where user accumulates pages (vs DataTable cursor buttons).
|
|
13
27
|
*/
|
|
14
|
-
export declare function InfiniteQueryState<TPage, TFlat
|
|
28
|
+
export declare function InfiniteQueryState<TPage, TFlat = TPage extends {
|
|
29
|
+
items: (infer TItem)[];
|
|
30
|
+
} ? TItem[] : unknown>({ query, skeleton, empty, flatten, isEmpty, errorRenderer, showRetry, onRetry, onAuthError, loadingMore, loadMore, showLoadMore, children, }: InfiniteQueryStateProp<TPage, TFlat>): React.JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Shared control sizing — reads `--control-height`, `--font-size-*` from density / theme. */
|
|
2
|
-
export declare const controlMultilineClass = "ui-control-multiline aria-invalid:border-destructive data-[status=error]:border-destructive data-[status=warning]:border-warning w-full rounded-[var(--control-radius)]
|
|
2
|
+
export declare const controlMultilineClass = "ui-control-multiline ui-control-outlined-surface aria-invalid:border-destructive data-[status=error]:border-destructive data-[status=warning]:border-warning w-full rounded-[var(--control-radius)] ring-offset-background placeholder:text-muted-foreground";
|
|
3
3
|
/**
|
|
4
4
|
* Multiline control with its own chrome removed, for a textarea EMBEDDED in a surface that already
|
|
5
5
|
* draws the box — a chat composer inside a Card, an inline edit cell, a comment box in a panel.
|
|
@@ -9,10 +9,10 @@ export declare const controlMultilineGhostClass = "ui-control-multiline data-[st
|
|
|
9
9
|
/**
|
|
10
10
|
* Multiline control drawn as antd's `filled` variant — a tinted surface instead of a boundary.
|
|
11
11
|
*
|
|
12
|
-
* It is a SEPARATE string rather than `controlMultilineClass` plus a modifier because
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* It is a SEPARATE string rather than `controlMultilineClass` plus a modifier because the two
|
|
13
|
+
* surfaces are alternatives, not a base plus a modifier: appending `.ui-control--filled` to the
|
|
14
|
+
* outlined list would put two same-layer rules on one element and leave the winner to source order.
|
|
15
|
+
* The two lists differ only in which chrome class they carry.
|
|
16
16
|
*/
|
|
17
17
|
export declare const controlMultilineFilledClass = "ui-control-multiline ui-control--filled aria-invalid:border-destructive data-[status=error]:border-destructive data-[status=warning]:border-warning w-full rounded-[var(--control-radius)] ring-offset-background placeholder:text-muted-foreground";
|
|
18
18
|
/**
|
|
@@ -47,7 +47,15 @@ export declare const controlOpenRingClass = "ui-control-trigger";
|
|
|
47
47
|
* The clamp keeps it to one line, so a wrappable value cannot grow the control.
|
|
48
48
|
*/
|
|
49
49
|
export declare const controlTriggerBaseClass = "ui-control ui-control-trigger flex items-center justify-between gap-2 whitespace-nowrap rounded-[var(--control-radius)] transition-[color,box-shadow] [&>[data-slot=select-value]]:line-clamp-1 [&>[data-slot=select-value]]:whitespace-normal [&>[data-slot=select-value]]:text-ellipsis";
|
|
50
|
-
|
|
50
|
+
/**
|
|
51
|
+
* The trigger WITH the resting surface — `.ui-control-outlined-surface`, which paints the identical
|
|
52
|
+
* border and fill from `--control-surface-border-color` / `--control-surface-background`.
|
|
53
|
+
*
|
|
54
|
+
* It used to be the two Tailwind utilities `border-input bg-background`, and `@layer utilities`
|
|
55
|
+
* outranks `@layer components`, so those two tokens could not reach it (gh#880). The painted result
|
|
56
|
+
* is unchanged; what changed is that a theme can now reach it.
|
|
57
|
+
*/
|
|
58
|
+
export declare const controlTriggerClass = "ui-control ui-control-trigger flex items-center justify-between gap-2 whitespace-nowrap rounded-[var(--control-radius)] transition-[color,box-shadow] [&>[data-slot=select-value]]:line-clamp-1 [&>[data-slot=select-value]]:whitespace-normal [&>[data-slot=select-value]]:text-ellipsis ui-control-outlined-surface";
|
|
51
59
|
/** `controlTriggerBaseClass` + the token-driven surface — the select-family trigger. */
|
|
52
60
|
export declare const controlSurfaceTriggerClass = "ui-control ui-control-trigger flex items-center justify-between gap-2 whitespace-nowrap rounded-[var(--control-radius)] transition-[color,box-shadow] [&>[data-slot=select-value]]:line-clamp-1 [&>[data-slot=select-value]]:whitespace-normal [&>[data-slot=select-value]]:text-ellipsis ui-control-surface";
|
|
53
61
|
export declare const controlIconClass = "size-[length:var(--control-height)] shrink-0";
|
|
@@ -59,15 +67,27 @@ export declare const tableHeadHeightClass = "h-[length:var(--table-row-height)]"
|
|
|
59
67
|
export declare const tableCellPaddingClass = "py-[length:var(--table-cell-padding-y)]";
|
|
60
68
|
/** Semantic status / badge tones — always use tokens, never raw Tailwind palette. The TEXT uses the
|
|
61
69
|
* AA-strong status colours (text-*-strong, darker than the fill) so a small status label clears
|
|
62
|
-
* WCAG AA on the soft tint; the border
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
* WCAG AA on the soft tint; the border keeps the brighter wa-iro role.
|
|
71
|
+
*
|
|
72
|
+
* THE FILL IS AN ARBITRARY PROPERTY, NOT `bg-success/10`, AND THAT IS THE WHOLE OF gh#866 HERE.
|
|
73
|
+
* `bg-<role>/10` can only ever be the role at 10% — a derivation — so a brand that ships an
|
|
74
|
+
* independently chosen pale surface (`--success #126342` with `--success-soft #E8F5EF`, a mint
|
|
75
|
+
* that is not that green at any alpha) could not reach the chip. `[background-color:…]` is the
|
|
76
|
+
* same utility layer and the same specificity as the class it replaces, so nothing about the
|
|
77
|
+
* cascade moves; it just reads `--surface-<role>` first and falls back to the wash Tailwind itself emits,
|
|
78
|
+
* `color-mix(in oklab, … 10%, transparent)` — the verbose spelling is deliberate, because
|
|
79
|
+
* `hsl(var(--success) / 0.1)` rasterises one 8-bit step off it on `warning` (252,245,225 vs
|
|
80
|
+
* 252,246,225 over the page ground) and "near enough" is not a default this repo ships.
|
|
81
|
+
* Written at the CALL SITE rather than bound at `:root`, per docs/TOKENS.md · "Role-mirror knobs
|
|
82
|
+
* MUST be `initial`", so a scoped `[data-tenant]` reaches it instead of freezing on `<html>`. */
|
|
83
|
+
export declare const toneSuccessClass = "border-success/30 [background-color:var(--surface-success,color-mix(in_oklab,hsl(var(--success))_10%,transparent))] text-success-strong";
|
|
84
|
+
export declare const toneWarningClass = "border-warning/30 [background-color:var(--surface-warning,color-mix(in_oklab,hsl(var(--warning))_10%,transparent))] text-warning-strong";
|
|
85
|
+
export declare const toneInfoClass = "border-info/30 [background-color:var(--surface-info,color-mix(in_oklab,hsl(var(--info))_10%,transparent))] text-info-strong";
|
|
66
86
|
/** Soft BRAND pill — a tinted primary tone (border/fill keep the brand role; the TEXT uses the
|
|
67
87
|
* AA-strong brand colour `text-primary-strong`, darker than the fill, so a small brand label clears
|
|
68
88
|
* WCAG AA on the soft tint — `text-primary` alone is only 4.04:1 in light). For a SOLID brand fill
|
|
69
89
|
* use the Badge `default` variant instead. */
|
|
70
90
|
export declare const tonePrimaryClass = "border-primary/30 bg-primary/10 text-primary-strong";
|
|
71
|
-
export declare const toneDestructiveClass = "border-destructive/30
|
|
91
|
+
export declare const toneDestructiveClass = "border-destructive/30 [background-color:var(--surface-destructive,color-mix(in_oklab,hsl(var(--destructive))_10%,transparent))] text-error-strong";
|
|
72
92
|
export declare const toneMutedClass = "border-border bg-muted text-muted-foreground";
|
|
73
93
|
export declare const toneNeutralClass = "border-border bg-muted text-muted-foreground";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const controlMultilineClass = "ui-control-multiline aria-invalid:border-destructive data-[status=error]:border-destructive data-[status=warning]:border-warning w-full rounded-[var(--control-radius)]
|
|
1
|
+
const controlMultilineClass = "ui-control-multiline ui-control-outlined-surface aria-invalid:border-destructive data-[status=error]:border-destructive data-[status=warning]:border-warning w-full rounded-[var(--control-radius)] ring-offset-background placeholder:text-muted-foreground";
|
|
2
2
|
const controlMultilineGhostClass = "ui-control-multiline data-[status=error]:border-destructive data-[status=warning]:border-warning w-full min-h-0 border-0 bg-transparent shadow-none placeholder:text-muted-foreground focus-visible:ring-0";
|
|
3
3
|
const controlMultilineFilledClass = "ui-control-multiline ui-control--filled aria-invalid:border-destructive data-[status=error]:border-destructive data-[status=warning]:border-warning w-full rounded-[var(--control-radius)] ring-offset-background placeholder:text-muted-foreground";
|
|
4
4
|
const controlOpenRingClass = "ui-control-trigger";
|
|
5
5
|
const controlTriggerBaseClass = "ui-control ui-control-trigger flex items-center justify-between gap-2 whitespace-nowrap rounded-[var(--control-radius)] transition-[color,box-shadow] [&>[data-slot=select-value]]:line-clamp-1 [&>[data-slot=select-value]]:whitespace-normal [&>[data-slot=select-value]]:text-ellipsis";
|
|
6
|
-
const controlTriggerClass = `${controlTriggerBaseClass}
|
|
6
|
+
const controlTriggerClass = `${controlTriggerBaseClass} ui-control-outlined-surface`;
|
|
7
7
|
const controlSurfaceTriggerClass = `${controlTriggerBaseClass} ui-control-surface`;
|
|
8
8
|
const controlIconClass = "size-[length:var(--control-height)] shrink-0";
|
|
9
9
|
const controlIconSmClass = "size-[calc(var(--control-height)-0.5rem)] shrink-0";
|
|
@@ -11,11 +11,11 @@ const controlIconLeadingClass = "size-[length:var(--control-icon-size)] shrink-0
|
|
|
11
11
|
const tableRowHeightClass = "h-[length:var(--table-row-height)]";
|
|
12
12
|
const tableHeadHeightClass = "h-[length:var(--table-row-height)]";
|
|
13
13
|
const tableCellPaddingClass = "py-[length:var(--table-cell-padding-y)]";
|
|
14
|
-
const toneSuccessClass = "border-success/30
|
|
15
|
-
const toneWarningClass = "border-warning/30
|
|
16
|
-
const toneInfoClass = "border-info/30
|
|
14
|
+
const toneSuccessClass = "border-success/30 [background-color:var(--surface-success,color-mix(in_oklab,hsl(var(--success))_10%,transparent))] text-success-strong";
|
|
15
|
+
const toneWarningClass = "border-warning/30 [background-color:var(--surface-warning,color-mix(in_oklab,hsl(var(--warning))_10%,transparent))] text-warning-strong";
|
|
16
|
+
const toneInfoClass = "border-info/30 [background-color:var(--surface-info,color-mix(in_oklab,hsl(var(--info))_10%,transparent))] text-info-strong";
|
|
17
17
|
const tonePrimaryClass = "border-primary/30 bg-primary/10 text-primary-strong";
|
|
18
|
-
const toneDestructiveClass = "border-destructive/30
|
|
18
|
+
const toneDestructiveClass = "border-destructive/30 [background-color:var(--surface-destructive,color-mix(in_oklab,hsl(var(--destructive))_10%,transparent))] text-error-strong";
|
|
19
19
|
const toneMutedClass = "border-border bg-muted text-muted-foreground";
|
|
20
20
|
const toneNeutralClass = "border-border bg-muted text-muted-foreground";
|
|
21
21
|
export {
|