@nextlyhq/ui 0.0.2-alpha.58 → 0.0.2-alpha.60
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/index.cjs +238 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +205 -71
- package/dist/index.d.ts +205 -71
- package/dist/index.mjs +234 -14
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.scoped.css +1 -1
- package/dist/theme.css +10 -0
- package/package.json +6 -5
package/dist/index.cjs
CHANGED
|
@@ -114,7 +114,11 @@ __export(src_exports, {
|
|
|
114
114
|
DropdownMenuSubContent: () => DropdownMenuSubContent,
|
|
115
115
|
DropdownMenuSubTrigger: () => DropdownMenuSubTrigger,
|
|
116
116
|
DropdownMenuTrigger: () => DropdownMenuTrigger,
|
|
117
|
+
FieldShell: () => FieldShell,
|
|
118
|
+
FormActions: () => FormActions,
|
|
117
119
|
FormLabelWithTooltip: () => FormLabelWithTooltip,
|
|
120
|
+
FormLayout: () => FormLayout,
|
|
121
|
+
FormSection: () => FormSection,
|
|
118
122
|
Grid: () => Grid,
|
|
119
123
|
Input: () => Input,
|
|
120
124
|
Label: () => Label,
|
|
@@ -489,7 +493,15 @@ var badgeVariants = (0, import_class_variance_authority3.cva)(
|
|
|
489
493
|
success: "bg-success-100 text-success-700 dark:bg-success-900 dark:text-success-100",
|
|
490
494
|
warning: "bg-warning-100 text-warning-700 dark:bg-warning-900 dark:text-warning-100",
|
|
491
495
|
destructive: "bg-destructive-100 text-destructive-700 dark:bg-destructive-900 dark:text-destructive-100",
|
|
492
|
-
|
|
496
|
+
/*
|
|
497
|
+
* The border colour is NOT important-marked. The base sets no border
|
|
498
|
+
* colour, so nothing inside this component competes for it — the only
|
|
499
|
+
* thing a mark could win against is the caller's own class. Seven
|
|
500
|
+
* outline badges pass one, including a status pill whose comment gives
|
|
501
|
+
* a 3:1 contrast reason for the colour it asks for, and every one of
|
|
502
|
+
* them was being overridden without any sign that it had been.
|
|
503
|
+
*/
|
|
504
|
+
outline: "border border-border bg-transparent text-foreground dark:text-muted-foreground dark:border-border"
|
|
493
505
|
}
|
|
494
506
|
},
|
|
495
507
|
defaultVariants: {
|
|
@@ -665,6 +677,13 @@ var COLS = {
|
|
|
665
677
|
4: "grid-cols-4",
|
|
666
678
|
6: "grid-cols-6"
|
|
667
679
|
};
|
|
680
|
+
var RESPONSIVE_COLS = {
|
|
681
|
+
1: "grid-cols-1",
|
|
682
|
+
2: "grid-cols-1 @2xl:grid-cols-2",
|
|
683
|
+
3: "grid-cols-1 @2xl:grid-cols-3",
|
|
684
|
+
4: "grid-cols-1 @2xl:grid-cols-4",
|
|
685
|
+
6: "grid-cols-1 @2xl:grid-cols-6"
|
|
686
|
+
};
|
|
668
687
|
var Stack = (0, import_react7.forwardRef)(
|
|
669
688
|
({ direction = "col", gap = 4, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
670
689
|
"div",
|
|
@@ -682,14 +701,20 @@ var Stack = (0, import_react7.forwardRef)(
|
|
|
682
701
|
);
|
|
683
702
|
Stack.displayName = "Stack";
|
|
684
703
|
var Grid = (0, import_react7.forwardRef)(
|
|
685
|
-
({ cols = 2, gap = 4, className, ...
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
704
|
+
({ cols = 2, gap = 4, responsive = false, className, children, ...rest }, ref) => {
|
|
705
|
+
if (!responsive) {
|
|
706
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
707
|
+
"div",
|
|
708
|
+
{
|
|
709
|
+
ref,
|
|
710
|
+
className: cn("grid", COLS[cols], GAP[gap], className),
|
|
711
|
+
...rest,
|
|
712
|
+
children
|
|
713
|
+
}
|
|
714
|
+
);
|
|
691
715
|
}
|
|
692
|
-
|
|
716
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref, className: cn("@container", className), ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: cn("grid", RESPONSIVE_COLS[cols], GAP[gap]), children }) });
|
|
717
|
+
}
|
|
693
718
|
);
|
|
694
719
|
Grid.displayName = "Grid";
|
|
695
720
|
var Stat = (0, import_react7.forwardRef)(
|
|
@@ -1149,7 +1174,20 @@ var tabsListVariants = (0, import_class_variance_authority8.cva)(
|
|
|
1149
1174
|
// `gap-1` and `p-0` are invariant across the variants, so they belong here —
|
|
1150
1175
|
// repeating them in each arm gives any future adjustment two sites to change
|
|
1151
1176
|
// and one to forget.
|
|
1152
|
-
|
|
1177
|
+
//
|
|
1178
|
+
// The rail the triggers sit on, and it is load-bearing rather than
|
|
1179
|
+
// decoration. Each trigger draws a 2px border on its trailing edge and pulls
|
|
1180
|
+
// itself half a step onto this one: with no rail here, that pull put a 2px
|
|
1181
|
+
// line onto whatever followed the strip in the document, and above a rounded
|
|
1182
|
+
// panel that is the corner curve — a straight bar crossing an 8px arc. The
|
|
1183
|
+
// rail also gives an inactive tab somewhere to be inactive, which is what
|
|
1184
|
+
// makes the active one read as selected rather than as the only tab.
|
|
1185
|
+
//
|
|
1186
|
+
// Which edge is the trailing one depends on orientation, so the rail follows
|
|
1187
|
+
// it. Radix stamps `data-orientation` on the list and on every trigger, so
|
|
1188
|
+
// both halves read the same source and cannot disagree about the axis. A
|
|
1189
|
+
// fixed bottom rail draws a horizontal line beneath a vertical list.
|
|
1190
|
+
"inline-flex items-center justify-center gap-1 rounded-none border-b border-border p-0 text-muted-foreground data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:border-r",
|
|
1153
1191
|
{
|
|
1154
1192
|
variants: { variant: TABS_LIST_VARIANTS },
|
|
1155
1193
|
defaultVariants: { variant: "default" }
|
|
@@ -1170,9 +1208,22 @@ var TABS_TRIGGER_SIZES = {
|
|
|
1170
1208
|
sm: "text-xs"
|
|
1171
1209
|
};
|
|
1172
1210
|
var tabsTriggerVariants = (0, import_class_variance_authority8.cva)(
|
|
1173
|
-
// Square corners: the active state is a 2px
|
|
1174
|
-
// full
|
|
1175
|
-
|
|
1211
|
+
// Square corners: the active state is a 2px border on the trailing edge that
|
|
1212
|
+
// has to run the full length of the trigger and stay flush with its ends.
|
|
1213
|
+
//
|
|
1214
|
+
// The active colour is NOT important-marked. Nothing inside this component
|
|
1215
|
+
// competes for it — the inactive arm is mutually exclusive with the active
|
|
1216
|
+
// one — so the only thing an `!` could win against is a caller's class, which
|
|
1217
|
+
// is precisely what a theme supplies. Marking it made the one line under
|
|
1218
|
+
// every selected tab the one line a theme could not restyle, and the failure
|
|
1219
|
+
// read as "the theme did not apply here" rather than as an opt-out.
|
|
1220
|
+
//
|
|
1221
|
+
// The trailing edge is the bottom when the strip is horizontal and the right
|
|
1222
|
+
// when it is vertical, so the indicator, the half-step pull onto the rail and
|
|
1223
|
+
// the active colour all switch axis together off the same `data-orientation`
|
|
1224
|
+
// the list reads. Switching only some of them puts the selection affordance
|
|
1225
|
+
// on one axis and the line it sits on the other.
|
|
1226
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-none bg-transparent px-4 py-2 font-medium cursor-pointer transition-all duration-200 border-b-2 relative -mb-0.5 data-[state=active]:border-b-primary data-[state=active]:text-primary data-[state=inactive]:border-transparent data-[state=inactive]:text-muted-foreground hover:text-primary hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:mb-0 data-[orientation=vertical]:border-r-2 data-[orientation=vertical]:-mr-0.5 data-[orientation=vertical]:data-[state=active]:border-r-primary",
|
|
1176
1227
|
{
|
|
1177
1228
|
variants: { size: TABS_TRIGGER_SIZES },
|
|
1178
1229
|
defaultVariants: { size: "default" }
|
|
@@ -1790,7 +1841,9 @@ var DialogPrimitive2 = __toESM(require("@radix-ui/react-dialog"), 1);
|
|
|
1790
1841
|
var import_class_variance_authority11 = require("class-variance-authority");
|
|
1791
1842
|
var React7 = __toESM(require("react"), 1);
|
|
1792
1843
|
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1793
|
-
var
|
|
1844
|
+
var SheetModalContext = React7.createContext(true);
|
|
1845
|
+
var Sheet = ({ modal = true, children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SheetModalContext.Provider, { value: modal, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DialogPrimitive2.Root, { modal, ...props, children }) });
|
|
1846
|
+
Sheet.displayName = "Sheet";
|
|
1794
1847
|
var SheetTrigger = DialogPrimitive2.Trigger;
|
|
1795
1848
|
var SheetClose = DialogPrimitive2.Close;
|
|
1796
1849
|
var SheetPortal = DialogPrimitive2.Portal;
|
|
@@ -1831,8 +1884,9 @@ var sheetVariants = (0, import_class_variance_authority11.cva)(
|
|
|
1831
1884
|
);
|
|
1832
1885
|
var SheetContent = React7.forwardRef(({ side = "right", className, children, ...props }, ref) => {
|
|
1833
1886
|
const portalContainer = usePortalContainer();
|
|
1887
|
+
const modal = React7.useContext(SheetModalContext);
|
|
1834
1888
|
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(SheetPortal, { container: portalContainer, children: [
|
|
1835
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SheetOverlay, {}),
|
|
1889
|
+
modal ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SheetOverlay, {}) : null,
|
|
1836
1890
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1837
1891
|
DialogPrimitive2.Content,
|
|
1838
1892
|
{
|
|
@@ -4066,6 +4120,172 @@ function useActiveShortcuts() {
|
|
|
4066
4120
|
manager.activeBindings
|
|
4067
4121
|
);
|
|
4068
4122
|
}
|
|
4123
|
+
|
|
4124
|
+
// src/components/field-shell.tsx
|
|
4125
|
+
var import_class_variance_authority13 = require("class-variance-authority");
|
|
4126
|
+
var import_react19 = require("react");
|
|
4127
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
4128
|
+
var controlWidth = (0, import_class_variance_authority13.cva)("w-full", {
|
|
4129
|
+
variants: {
|
|
4130
|
+
width: {
|
|
4131
|
+
half: "max-w-[var(--nx-field-half,380px)]",
|
|
4132
|
+
full: "max-w-[var(--nx-field-full,760px)]",
|
|
4133
|
+
fill: ""
|
|
4134
|
+
}
|
|
4135
|
+
},
|
|
4136
|
+
defaultVariants: { width: "half" }
|
|
4137
|
+
});
|
|
4138
|
+
function readControlProps(child) {
|
|
4139
|
+
const props = child.props;
|
|
4140
|
+
return props && typeof props === "object" ? props : {};
|
|
4141
|
+
}
|
|
4142
|
+
function isRenderFunction(children) {
|
|
4143
|
+
return typeof children === "function";
|
|
4144
|
+
}
|
|
4145
|
+
function computeControlWiring(ownProps, requestedId, renderedMessageIds, hasError) {
|
|
4146
|
+
const ownId = typeof ownProps.id === "string" && ownProps.id !== "" ? ownProps.id : void 0;
|
|
4147
|
+
const id = ownId ?? requestedId;
|
|
4148
|
+
const ownDescribedByIds = typeof ownProps["aria-describedby"] === "string" ? ownProps["aria-describedby"].split(" ").filter(Boolean) : [];
|
|
4149
|
+
const describedByIds = Array.from(
|
|
4150
|
+
/* @__PURE__ */ new Set([...ownDescribedByIds, ...renderedMessageIds])
|
|
4151
|
+
);
|
|
4152
|
+
const describedBy = describedByIds.length > 0 ? describedByIds.join(" ") : void 0;
|
|
4153
|
+
const ownInvalid = typeof ownProps["aria-invalid"] === "boolean" ? ownProps["aria-invalid"] : void 0;
|
|
4154
|
+
const invalid = hasError ? true : ownInvalid;
|
|
4155
|
+
return { id, describedBy, invalid };
|
|
4156
|
+
}
|
|
4157
|
+
function FieldShell({
|
|
4158
|
+
label,
|
|
4159
|
+
description,
|
|
4160
|
+
error,
|
|
4161
|
+
width = "half",
|
|
4162
|
+
htmlFor,
|
|
4163
|
+
className,
|
|
4164
|
+
children
|
|
4165
|
+
}) {
|
|
4166
|
+
const generatedControlId = (0, import_react19.useId)();
|
|
4167
|
+
const messageBaseId = (0, import_react19.useId)();
|
|
4168
|
+
const descriptionId = `${messageBaseId}-description`;
|
|
4169
|
+
const errorId = `${messageBaseId}-error`;
|
|
4170
|
+
const requestedId = htmlFor ?? generatedControlId;
|
|
4171
|
+
const renderedMessageIds = [
|
|
4172
|
+
description ? descriptionId : null,
|
|
4173
|
+
error ? errorId : null
|
|
4174
|
+
].filter((id) => id !== null);
|
|
4175
|
+
const wiring = isRenderFunction(children) ? computeControlWiring({}, requestedId, renderedMessageIds, Boolean(error)) : computeControlWiring(
|
|
4176
|
+
readControlProps(children),
|
|
4177
|
+
requestedId,
|
|
4178
|
+
renderedMessageIds,
|
|
4179
|
+
Boolean(error)
|
|
4180
|
+
);
|
|
4181
|
+
const isFragmentChild = !isRenderFunction(children) && children.type === import_react19.Fragment;
|
|
4182
|
+
(0, import_react19.useEffect)(() => {
|
|
4183
|
+
if (!isDevelopmentRuntime()) return;
|
|
4184
|
+
if (isFragmentChild) return;
|
|
4185
|
+
const landed = document.getElementById(wiring.id) !== null;
|
|
4186
|
+
const fieldName = typeof label === "string" ? `"${label}"` : "this field";
|
|
4187
|
+
devWarnOnce(
|
|
4188
|
+
landed,
|
|
4189
|
+
`FieldShell: the id computed for ${fieldName} never appeared on any element in the document, so its label and any description are not connected to the control. This happens when the control is a compound component \u2014 a Radix \`Select\`, \`RadioGroup\`, or similar \u2014 whose root does not forward \`id\`/\`aria-describedby\`/\`aria-invalid\` to a real DOM node. Pass \`children\` as a function and apply those to the control's actual focusable element (its trigger) instead of a single top-level clone.`
|
|
4190
|
+
);
|
|
4191
|
+
}, [wiring.id, label, isFragmentChild]);
|
|
4192
|
+
let control;
|
|
4193
|
+
if (isRenderFunction(children)) {
|
|
4194
|
+
control = children(wiring);
|
|
4195
|
+
} else {
|
|
4196
|
+
devWarnOnce(
|
|
4197
|
+
!isFragmentChild,
|
|
4198
|
+
"FieldShell: `children` must be a single element, not a Fragment. A Fragment forwards no props to the elements inside it, so the id, aria-describedby and aria-invalid this component computes would have nowhere to land \u2014 the label and the control would look wired up and never actually connect. Wrap the intended elements in a real element instead, such as a `<div>`."
|
|
4199
|
+
);
|
|
4200
|
+
const controlOverrides = {
|
|
4201
|
+
id: wiring.id,
|
|
4202
|
+
...wiring.describedBy !== void 0 ? { "aria-describedby": wiring.describedBy } : {},
|
|
4203
|
+
...wiring.invalid !== void 0 ? { "aria-invalid": wiring.invalid } : {}
|
|
4204
|
+
};
|
|
4205
|
+
control = isFragmentChild ? children : (0, import_react19.cloneElement)(children, controlOverrides);
|
|
4206
|
+
}
|
|
4207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: cn("flex flex-col gap-1.5", className), children: [
|
|
4208
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
4209
|
+
"label",
|
|
4210
|
+
{
|
|
4211
|
+
htmlFor: wiring.id,
|
|
4212
|
+
className: "text-sm font-medium text-foreground",
|
|
4213
|
+
children: label
|
|
4214
|
+
}
|
|
4215
|
+
) : null,
|
|
4216
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: controlWidth({ width }), children: control }),
|
|
4217
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { id: descriptionId, className: "text-sm text-muted-foreground", children: description }) : null,
|
|
4218
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { id: errorId, className: "text-sm font-medium text-destructive", children: error }) : null
|
|
4219
|
+
] });
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
// src/components/form-section.tsx
|
|
4223
|
+
var import_react20 = require("react");
|
|
4224
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
4225
|
+
function FormSection({
|
|
4226
|
+
label,
|
|
4227
|
+
description,
|
|
4228
|
+
className,
|
|
4229
|
+
children
|
|
4230
|
+
}) {
|
|
4231
|
+
const labelId = (0, import_react20.useId)();
|
|
4232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("section", { "aria-labelledby": labelId, className: cn("space-y-2", className), children: [
|
|
4233
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "space-y-1", children: [
|
|
4234
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
4235
|
+
"p",
|
|
4236
|
+
{
|
|
4237
|
+
id: labelId,
|
|
4238
|
+
className: "text-xs font-semibold tracking-[0.08em] uppercase text-muted-foreground",
|
|
4239
|
+
children: label
|
|
4240
|
+
}
|
|
4241
|
+
),
|
|
4242
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-sm text-muted-foreground", children: description }) : null
|
|
4243
|
+
] }),
|
|
4244
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Card, { className: "overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "divide-y divide-foreground/10 px-6", children }) })
|
|
4245
|
+
] });
|
|
4246
|
+
}
|
|
4247
|
+
|
|
4248
|
+
// src/components/form-layout.tsx
|
|
4249
|
+
var import_class_variance_authority14 = require("class-variance-authority");
|
|
4250
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
4251
|
+
var measure = (0, import_class_variance_authority14.cva)("mx-auto w-full px-6 py-8", {
|
|
4252
|
+
variants: {
|
|
4253
|
+
width: {
|
|
4254
|
+
form: "max-w-[56rem]",
|
|
4255
|
+
wide: "max-w-[72rem]"
|
|
4256
|
+
}
|
|
4257
|
+
},
|
|
4258
|
+
defaultVariants: { width: "form" }
|
|
4259
|
+
});
|
|
4260
|
+
function FormLayout({
|
|
4261
|
+
width = "form",
|
|
4262
|
+
className,
|
|
4263
|
+
children
|
|
4264
|
+
}) {
|
|
4265
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: cn(measure({ width }), className), children });
|
|
4266
|
+
}
|
|
4267
|
+
function FormActions({ dirty, className, children }) {
|
|
4268
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
4269
|
+
"div",
|
|
4270
|
+
{
|
|
4271
|
+
className: cn(
|
|
4272
|
+
"sticky bottom-0 mt-8 flex items-center justify-end gap-3",
|
|
4273
|
+
"border-t border-border bg-background/95 py-4 backdrop-blur",
|
|
4274
|
+
className
|
|
4275
|
+
),
|
|
4276
|
+
children: [
|
|
4277
|
+
dirty ? (
|
|
4278
|
+
// `role="status"` (implying `aria-live="polite"`) so a screen-reader
|
|
4279
|
+
// user is told when the flag flips false to true, not only sighted
|
|
4280
|
+
// users watching the bar. This is the only live region FormActions
|
|
4281
|
+
// renders, one per form.
|
|
4282
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { role: "status", className: "mr-auto text-sm text-muted-foreground", children: "You have unsaved changes" })
|
|
4283
|
+
) : null,
|
|
4284
|
+
children
|
|
4285
|
+
]
|
|
4286
|
+
}
|
|
4287
|
+
);
|
|
4288
|
+
}
|
|
4069
4289
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4070
4290
|
0 && (module.exports = {
|
|
4071
4291
|
Accordion,
|
|
@@ -4151,7 +4371,11 @@ function useActiveShortcuts() {
|
|
|
4151
4371
|
DropdownMenuSubContent,
|
|
4152
4372
|
DropdownMenuSubTrigger,
|
|
4153
4373
|
DropdownMenuTrigger,
|
|
4374
|
+
FieldShell,
|
|
4375
|
+
FormActions,
|
|
4154
4376
|
FormLabelWithTooltip,
|
|
4377
|
+
FormLayout,
|
|
4378
|
+
FormSection,
|
|
4155
4379
|
Grid,
|
|
4156
4380
|
Input,
|
|
4157
4381
|
Label,
|