@lucasvu/scope-ui 0.0.1 → 0.0.2
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/README.md +84 -15
- package/dist/index.cjs +497 -6
- package/dist/index.d.cts +107 -5
- package/dist/index.d.ts +107 -5
- package/dist/index.js +489 -7
- package/dist/styles.css +2 -2
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -457,6 +457,7 @@ var Button = react.forwardRef(
|
|
|
457
457
|
disabled,
|
|
458
458
|
startIcon,
|
|
459
459
|
endIcon,
|
|
460
|
+
block = false,
|
|
460
461
|
className,
|
|
461
462
|
style,
|
|
462
463
|
children,
|
|
@@ -469,14 +470,14 @@ var Button = react.forwardRef(
|
|
|
469
470
|
const describedBy = [helperId, errorId].filter(Boolean).join(" ") || void 0;
|
|
470
471
|
const content = children ?? label;
|
|
471
472
|
const isDisabled = disabled || loading;
|
|
472
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", style, children: [
|
|
473
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1", block && "w-full"), style, children: [
|
|
473
474
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
474
475
|
"button",
|
|
475
476
|
{
|
|
476
477
|
ref,
|
|
477
478
|
id: buttonId,
|
|
478
479
|
type: type ?? "button",
|
|
479
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
480
|
+
className: cn(buttonVariants({ variant, size, className }), block && "w-full"),
|
|
480
481
|
disabled: isDisabled,
|
|
481
482
|
"aria-describedby": describedBy,
|
|
482
483
|
"aria-busy": loading || void 0,
|
|
@@ -897,6 +898,94 @@ var NumericInput = react.forwardRef(
|
|
|
897
898
|
}
|
|
898
899
|
);
|
|
899
900
|
NumericInput.displayName = "NumericInput";
|
|
901
|
+
var textareaVariants = classVarianceAuthority.cva(
|
|
902
|
+
"flex min-h-[104px] w-full resize-y rounded-md border px-3 py-2 text-sm font-medium transition placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-60",
|
|
903
|
+
{
|
|
904
|
+
variants: {
|
|
905
|
+
variant: {
|
|
906
|
+
default: "border-input bg-background text-foreground hover:border-border",
|
|
907
|
+
ghost: "border-transparent bg-transparent text-foreground focus-visible:border-border/60",
|
|
908
|
+
outline: "border border-border bg-transparent text-foreground"
|
|
909
|
+
},
|
|
910
|
+
size: {
|
|
911
|
+
sm: "min-h-[88px] text-sm",
|
|
912
|
+
md: "min-h-[104px] text-sm",
|
|
913
|
+
lg: "min-h-[120px] text-base"
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
defaultVariants: {
|
|
917
|
+
variant: "default",
|
|
918
|
+
size: "md"
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
);
|
|
922
|
+
var Textarea = react.forwardRef(
|
|
923
|
+
({
|
|
924
|
+
variant = "default",
|
|
925
|
+
size = "md",
|
|
926
|
+
label,
|
|
927
|
+
helperText,
|
|
928
|
+
errorMessage,
|
|
929
|
+
loading,
|
|
930
|
+
disabled,
|
|
931
|
+
className,
|
|
932
|
+
style,
|
|
933
|
+
textareaClassName,
|
|
934
|
+
id,
|
|
935
|
+
onChange,
|
|
936
|
+
onValueChange,
|
|
937
|
+
suffix,
|
|
938
|
+
rows,
|
|
939
|
+
...rest
|
|
940
|
+
}, ref) => {
|
|
941
|
+
const generatedId = react.useId();
|
|
942
|
+
const textareaId = id ?? generatedId;
|
|
943
|
+
const helperId = helperText ? `${textareaId}-helper` : void 0;
|
|
944
|
+
const errorId = errorMessage ? `${textareaId}-error` : void 0;
|
|
945
|
+
const hasRightAccessory = Boolean(suffix) || Boolean(loading);
|
|
946
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
947
|
+
FieldWrapper,
|
|
948
|
+
{
|
|
949
|
+
label,
|
|
950
|
+
helperText,
|
|
951
|
+
errorMessage,
|
|
952
|
+
helperId,
|
|
953
|
+
errorId,
|
|
954
|
+
htmlFor: textareaId,
|
|
955
|
+
className,
|
|
956
|
+
style,
|
|
957
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
|
|
958
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
959
|
+
"textarea",
|
|
960
|
+
{
|
|
961
|
+
id: textareaId,
|
|
962
|
+
ref,
|
|
963
|
+
rows: rows ?? 4,
|
|
964
|
+
className: cn(
|
|
965
|
+
textareaVariants({ variant, size }),
|
|
966
|
+
hasRightAccessory && "pr-10",
|
|
967
|
+
textareaClassName
|
|
968
|
+
),
|
|
969
|
+
disabled: disabled || loading,
|
|
970
|
+
"aria-invalid": Boolean(errorMessage),
|
|
971
|
+
"aria-describedby": [helperId, errorId].filter(Boolean).join(" ") || void 0,
|
|
972
|
+
onChange: (event) => {
|
|
973
|
+
onChange?.(event);
|
|
974
|
+
onValueChange?.(event.target.value);
|
|
975
|
+
},
|
|
976
|
+
...rest
|
|
977
|
+
}
|
|
978
|
+
),
|
|
979
|
+
hasRightAccessory ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pointer-events-none absolute right-3 top-3 flex items-center gap-2 text-muted-foreground", children: [
|
|
980
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { size: "xs" }) : null,
|
|
981
|
+
suffix ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: suffix }) : null
|
|
982
|
+
] }) : null
|
|
983
|
+
] })
|
|
984
|
+
}
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
);
|
|
988
|
+
Textarea.displayName = "Textarea";
|
|
900
989
|
function Card({ className, ...props }) {
|
|
901
990
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
902
991
|
"div",
|
|
@@ -1802,9 +1891,18 @@ function CheckMark() {
|
|
|
1802
1891
|
function Form({ className, ...props }) {
|
|
1803
1892
|
return /* @__PURE__ */ jsxRuntime.jsx("form", { className: cn("space-y-6", className), ...props });
|
|
1804
1893
|
}
|
|
1805
|
-
var FormField = react.forwardRef(
|
|
1806
|
-
|
|
1807
|
-
|
|
1894
|
+
var FormField = react.forwardRef(
|
|
1895
|
+
({ className, label, helperText, errorMessage, required, htmlFor, children, ...props }, ref) => {
|
|
1896
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("grid gap-2", className), ...props, children: [
|
|
1897
|
+
label ? /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor, className: "text-sm font-semibold leading-none text-foreground", children: [
|
|
1898
|
+
label,
|
|
1899
|
+
required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-destructive", children: "*" }) : null
|
|
1900
|
+
] }) : null,
|
|
1901
|
+
children,
|
|
1902
|
+
errorMessage ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: errorMessage }) : helperText ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: helperText }) : null
|
|
1903
|
+
] });
|
|
1904
|
+
}
|
|
1905
|
+
);
|
|
1808
1906
|
FormField.displayName = "FormField";
|
|
1809
1907
|
var FormItem = react.forwardRef(({ className, ...props }, ref) => {
|
|
1810
1908
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col space-y-2", className), ...props });
|
|
@@ -2031,6 +2129,13 @@ var SearchableSelect = react.forwardRef(
|
|
|
2031
2129
|
return candidate.toLowerCase().includes(normalized);
|
|
2032
2130
|
});
|
|
2033
2131
|
}, [options, searchTerm]);
|
|
2132
|
+
const normalizeValue = react.useCallback(
|
|
2133
|
+
(raw) => {
|
|
2134
|
+
const match = options.find((option) => String(option.value) === raw);
|
|
2135
|
+
return match ? match.value : raw;
|
|
2136
|
+
},
|
|
2137
|
+
[options]
|
|
2138
|
+
);
|
|
2034
2139
|
const handleOpenChange = react.useCallback(
|
|
2035
2140
|
(next) => {
|
|
2036
2141
|
setIsOpen(next);
|
|
@@ -2074,7 +2179,7 @@ var SearchableSelect = react.forwardRef(
|
|
|
2074
2179
|
{
|
|
2075
2180
|
value: value !== void 0 ? String(value) : void 0,
|
|
2076
2181
|
defaultValue: defaultValue !== void 0 ? String(defaultValue) : void 0,
|
|
2077
|
-
onValueChange: (next) => onChange?.(next),
|
|
2182
|
+
onValueChange: (next) => onChange?.(normalizeValue(next)),
|
|
2078
2183
|
disabled: disabled || loading,
|
|
2079
2184
|
onOpenChange: handleOpenChange,
|
|
2080
2185
|
...props,
|
|
@@ -6535,6 +6640,383 @@ function PageTitle2({
|
|
|
6535
6640
|
);
|
|
6536
6641
|
}
|
|
6537
6642
|
|
|
6643
|
+
// src/ai-manifest.ts
|
|
6644
|
+
var uiAiManifest = {
|
|
6645
|
+
packageName: "@lucasvu/scope-ui",
|
|
6646
|
+
styleImport: "@lucasvu/scope-ui/styles.css",
|
|
6647
|
+
rules: [
|
|
6648
|
+
"Import the stylesheet once at the app entry before rendering any component.",
|
|
6649
|
+
"Prefer the canonical component for each intent instead of mixing legacy MainFe components.",
|
|
6650
|
+
"Use Input/Textarea/Select label props directly for simple fields; use Field only to wrap custom controls or grouped content.",
|
|
6651
|
+
"Use Select for small fixed option lists, SearchableSelect for larger local lists, Combobox for type-and-pick flows, and AsyncCombobox for remote search.",
|
|
6652
|
+
'Always provide a stable rowKey to DataTable and use sortMode="server" when sorting happens on the backend.',
|
|
6653
|
+
"Prefer Card as the outer layout section and keep alerts, stats, and tables inside CardContent when building dashboards or forms.",
|
|
6654
|
+
"Do not import MainFe components unless the target explicitly asks for legacy main-fe styling."
|
|
6655
|
+
],
|
|
6656
|
+
components: [
|
|
6657
|
+
{
|
|
6658
|
+
name: "Primary action",
|
|
6659
|
+
importName: "Button",
|
|
6660
|
+
purpose: "Render the main clickable action.",
|
|
6661
|
+
useWhen: [
|
|
6662
|
+
"Submitting a form",
|
|
6663
|
+
"Triggering create/save/confirm flows",
|
|
6664
|
+
"Need loading or block width support"
|
|
6665
|
+
],
|
|
6666
|
+
avoidWhen: [
|
|
6667
|
+
"Pure navigation text links without button semantics"
|
|
6668
|
+
],
|
|
6669
|
+
props: [
|
|
6670
|
+
{ name: "variant", type: "'default' | 'secondary' | 'ghost' | 'outline' | 'destructive' | 'link' | 'confirm' | 'create'", description: "Chooses the visual emphasis." },
|
|
6671
|
+
{ name: "size", type: "'sm' | 'md' | 'lg' | 'icon'", description: "Chooses the button size." },
|
|
6672
|
+
{ name: "block", type: "boolean", description: "Expands the button to full width." },
|
|
6673
|
+
{ name: "loading", type: "boolean", description: "Shows a spinner and disables interaction." }
|
|
6674
|
+
],
|
|
6675
|
+
example: "<Button variant='create' block>Save changes</Button>",
|
|
6676
|
+
related: ["Alert", "Card"]
|
|
6677
|
+
},
|
|
6678
|
+
{
|
|
6679
|
+
name: "Single-line text input",
|
|
6680
|
+
importName: "Input",
|
|
6681
|
+
purpose: "Capture short text, email, password, number-like strings, or search text.",
|
|
6682
|
+
useWhen: [
|
|
6683
|
+
"A single text value is needed",
|
|
6684
|
+
"You need label/helper/error handling built in",
|
|
6685
|
+
"You need prefix, suffix, or password toggle support"
|
|
6686
|
+
],
|
|
6687
|
+
props: [
|
|
6688
|
+
{ name: "label", type: "ReactNode", description: "Field label rendered above the control." },
|
|
6689
|
+
{ name: "helperText", type: "ReactNode", description: "Supplemental guidance shown below." },
|
|
6690
|
+
{ name: "errorMessage", type: "ReactNode", description: "Validation message shown below in error state." },
|
|
6691
|
+
{ name: "prefix", type: "ReactNode", description: "Visual prefix inside the field." },
|
|
6692
|
+
{ name: "suffix", type: "ReactNode", description: "Visual suffix inside the field." }
|
|
6693
|
+
],
|
|
6694
|
+
example: "<Input label='Email' type='email' placeholder='you@example.com' />",
|
|
6695
|
+
related: ["Textarea", "NumericInput", "Field"]
|
|
6696
|
+
},
|
|
6697
|
+
{
|
|
6698
|
+
name: "Multiline text input",
|
|
6699
|
+
importName: "Textarea",
|
|
6700
|
+
purpose: "Capture longer free-form content.",
|
|
6701
|
+
useWhen: [
|
|
6702
|
+
"The user needs multiple lines of text",
|
|
6703
|
+
"A description, note, or comment field is needed"
|
|
6704
|
+
],
|
|
6705
|
+
props: [
|
|
6706
|
+
{ name: "label", type: "ReactNode", description: "Field label rendered above the textarea." },
|
|
6707
|
+
{ name: "rows", type: "number", description: "Controls initial textarea height." },
|
|
6708
|
+
{ name: "helperText", type: "ReactNode", description: "Supplemental guidance shown below." },
|
|
6709
|
+
{ name: "errorMessage", type: "ReactNode", description: "Validation message shown below in error state." }
|
|
6710
|
+
],
|
|
6711
|
+
example: "<Textarea label='Description' rows={5} placeholder='Write the details...' />",
|
|
6712
|
+
related: ["Input", "Field"]
|
|
6713
|
+
},
|
|
6714
|
+
{
|
|
6715
|
+
name: "Single select",
|
|
6716
|
+
importName: "Select",
|
|
6717
|
+
purpose: "Pick one value from a small fixed option set.",
|
|
6718
|
+
useWhen: [
|
|
6719
|
+
"Fewer options and no search is required",
|
|
6720
|
+
"A simple dropdown is enough"
|
|
6721
|
+
],
|
|
6722
|
+
props: [
|
|
6723
|
+
{ name: "options", type: "SelectOption[]", required: true, description: "List of selectable options." },
|
|
6724
|
+
{ name: "label", type: "ReactNode", description: "Field label rendered above the trigger." },
|
|
6725
|
+
{ name: "placeholder", type: "string", description: "Placeholder shown when no value is selected." },
|
|
6726
|
+
{ name: "onChange", type: "(value) => void", description: "Returns the original option value type." }
|
|
6727
|
+
],
|
|
6728
|
+
example: "<Select label='Plan' options={[{ label: 'Starter', value: 'starter' }]} />",
|
|
6729
|
+
related: ["SearchableSelect", "Combobox"]
|
|
6730
|
+
},
|
|
6731
|
+
{
|
|
6732
|
+
name: "Searchable local select",
|
|
6733
|
+
importName: "SearchableSelect",
|
|
6734
|
+
purpose: "Pick one value from a larger in-memory list with search.",
|
|
6735
|
+
useWhen: [
|
|
6736
|
+
"More than a handful of options exist",
|
|
6737
|
+
"Local filtering is enough"
|
|
6738
|
+
],
|
|
6739
|
+
props: [
|
|
6740
|
+
{ name: "options", type: "SearchableSelectOption[]", required: true, description: "List of selectable options." },
|
|
6741
|
+
{ name: "searchPlaceholder", type: "string", description: "Placeholder inside the search field." },
|
|
6742
|
+
{ name: "onSearch", type: "(query) => void", description: "Receives the local search query." }
|
|
6743
|
+
],
|
|
6744
|
+
example: "<SearchableSelect label='Country' searchPlaceholder='Search country' options={countries} />",
|
|
6745
|
+
related: ["Select", "Combobox", "AsyncCombobox"]
|
|
6746
|
+
},
|
|
6747
|
+
{
|
|
6748
|
+
name: "Type and pick",
|
|
6749
|
+
importName: "Combobox",
|
|
6750
|
+
purpose: "Let the user type and choose from a filtered list.",
|
|
6751
|
+
useWhen: [
|
|
6752
|
+
"A command-palette-like input is needed",
|
|
6753
|
+
"The typed text should stay visible in the input"
|
|
6754
|
+
],
|
|
6755
|
+
props: [
|
|
6756
|
+
{ name: "options", type: "ComboboxOption[]", required: true, description: "List of options to filter." },
|
|
6757
|
+
{ name: "value", type: "string | number", description: "Selected value." },
|
|
6758
|
+
{ name: "onChange", type: "(value) => void", description: "Selected value callback." }
|
|
6759
|
+
],
|
|
6760
|
+
example: "<Combobox label='Assignee' options={users} value={assigneeId} onChange={setAssigneeId} />",
|
|
6761
|
+
related: ["SearchableSelect", "AsyncCombobox"]
|
|
6762
|
+
},
|
|
6763
|
+
{
|
|
6764
|
+
name: "Remote search combobox",
|
|
6765
|
+
importName: "AsyncCombobox",
|
|
6766
|
+
purpose: "Search and pick from server-backed data.",
|
|
6767
|
+
useWhen: [
|
|
6768
|
+
"Options are loaded from an API",
|
|
6769
|
+
"Infinite scroll or async fetching is needed"
|
|
6770
|
+
],
|
|
6771
|
+
props: [
|
|
6772
|
+
{ name: "options", type: "ComboboxOption[]", required: true, description: "Currently loaded options." },
|
|
6773
|
+
{ name: "loading", type: "boolean", description: "Shows async loading state." },
|
|
6774
|
+
{ name: "onSearch", type: "(query) => void", required: true, description: "Triggers remote search." },
|
|
6775
|
+
{ name: "onLoadMore", type: "() => void", description: "Loads more options when scrolling near the end." }
|
|
6776
|
+
],
|
|
6777
|
+
example: "<AsyncCombobox label='User' options={options} loading={loading} onSearch={searchUsers} />",
|
|
6778
|
+
related: ["Combobox", "SearchableSelect"]
|
|
6779
|
+
},
|
|
6780
|
+
{
|
|
6781
|
+
name: "Multiple selection",
|
|
6782
|
+
importName: "MultiSelect",
|
|
6783
|
+
purpose: "Choose many values from a searchable list.",
|
|
6784
|
+
useWhen: [
|
|
6785
|
+
"The user can pick multiple tags, users, or filters"
|
|
6786
|
+
],
|
|
6787
|
+
props: [
|
|
6788
|
+
{ name: "options", type: "MultiSelectOption[]", required: true, description: "List of selectable options." },
|
|
6789
|
+
{ name: "value", type: "Array<string | number>", description: "Selected values." },
|
|
6790
|
+
{ name: "onChange", type: "(values) => void", description: "Selected values callback." }
|
|
6791
|
+
],
|
|
6792
|
+
example: "<MultiSelect label='Tags' options={tagOptions} value={tags} onChange={setTags} />",
|
|
6793
|
+
related: ["Select", "SearchableSelect"]
|
|
6794
|
+
},
|
|
6795
|
+
{
|
|
6796
|
+
name: "Structured field wrapper",
|
|
6797
|
+
importName: "Field",
|
|
6798
|
+
purpose: "Add a shared label/helper/error wrapper around custom content.",
|
|
6799
|
+
useWhen: [
|
|
6800
|
+
"Wrapping a custom control that does not expose label props",
|
|
6801
|
+
"Grouping multiple controls under one heading"
|
|
6802
|
+
],
|
|
6803
|
+
avoidWhen: [
|
|
6804
|
+
"A built-in form control already renders its own label and helper text"
|
|
6805
|
+
],
|
|
6806
|
+
props: [
|
|
6807
|
+
{ name: "label", type: "ReactNode", description: "Field label rendered above children." },
|
|
6808
|
+
{ name: "helperText", type: "ReactNode", description: "Helper text below children." },
|
|
6809
|
+
{ name: "errorMessage", type: "ReactNode", description: "Error text below children." },
|
|
6810
|
+
{ name: "htmlFor", type: "string", description: "Associates the label with the wrapped control id." }
|
|
6811
|
+
],
|
|
6812
|
+
example: "<Field label='Schedule' htmlFor='range'><DateRangePicker id='range' /></Field>",
|
|
6813
|
+
related: ["Input", "Textarea", "Select"]
|
|
6814
|
+
},
|
|
6815
|
+
{
|
|
6816
|
+
name: "Data table",
|
|
6817
|
+
importName: "DataTable",
|
|
6818
|
+
purpose: "Render sortable tabular data with optional selection, actions, loading, and pagination.",
|
|
6819
|
+
useWhen: [
|
|
6820
|
+
"Displaying records in rows and columns",
|
|
6821
|
+
"Sort, pagination, selection, or row actions are required"
|
|
6822
|
+
],
|
|
6823
|
+
props: [
|
|
6824
|
+
{ name: "columns", type: "DataTableColumn<T>[]", required: true, description: "Column definitions." },
|
|
6825
|
+
{ name: "data", type: "T[]", required: true, description: "Rows to render." },
|
|
6826
|
+
{ name: "rowKey", type: "keyof T | ((record: T) => string | number)", required: true, description: "Stable key for each row." },
|
|
6827
|
+
{ name: "pagination", type: "DataTablePagination", description: "Enables pagination controls." },
|
|
6828
|
+
{ name: "sortMode", type: "'client' | 'server'", description: "Choose client or backend sorting." }
|
|
6829
|
+
],
|
|
6830
|
+
example: "<DataTable rowKey='id' columns={columns} data={rows} pagination={pagination} />",
|
|
6831
|
+
related: ["Card", "Pagination", "Loading"]
|
|
6832
|
+
},
|
|
6833
|
+
{
|
|
6834
|
+
name: "Status message",
|
|
6835
|
+
importName: "Alert",
|
|
6836
|
+
purpose: "Communicate neutral, success, warning, or danger states.",
|
|
6837
|
+
useWhen: [
|
|
6838
|
+
"You need a visible status or validation banner"
|
|
6839
|
+
],
|
|
6840
|
+
props: [
|
|
6841
|
+
{ name: "tone", type: "'neutral' | 'info' | 'success' | 'warning' | 'danger'", description: "Semantic tone mapping." },
|
|
6842
|
+
{ name: "title", type: "ReactNode", description: "Alert headline." },
|
|
6843
|
+
{ name: "description", type: "ReactNode", description: "Supporting message." }
|
|
6844
|
+
],
|
|
6845
|
+
example: "<Alert tone='warning' title='Missing information' description='Please fill all required fields.' />",
|
|
6846
|
+
related: ["Loading", "Card"]
|
|
6847
|
+
},
|
|
6848
|
+
{
|
|
6849
|
+
name: "Layout section",
|
|
6850
|
+
importName: "Card",
|
|
6851
|
+
purpose: "Wrap a coherent chunk of UI in a bordered surface.",
|
|
6852
|
+
useWhen: [
|
|
6853
|
+
"Building forms, dashboards, settings sections, or summary panels"
|
|
6854
|
+
],
|
|
6855
|
+
props: [
|
|
6856
|
+
{ name: "className", type: "string", description: "Adds layout-specific spacing or width." }
|
|
6857
|
+
],
|
|
6858
|
+
example: "<Card><CardHeader><CardTitle>Account</CardTitle></CardHeader><CardContent>...</CardContent></Card>",
|
|
6859
|
+
related: ["CardHeader", "CardTitle", "CardContent", "CardFooter"]
|
|
6860
|
+
}
|
|
6861
|
+
]
|
|
6862
|
+
};
|
|
6863
|
+
|
|
6864
|
+
// src/theme-contract.ts
|
|
6865
|
+
var uiThemeContract = {
|
|
6866
|
+
packageName: "@lucasvu/scope-ui",
|
|
6867
|
+
importOrder: [
|
|
6868
|
+
"import '@lucasvu/scope-ui/styles.css'",
|
|
6869
|
+
"import './styles/ui-theme.css'"
|
|
6870
|
+
],
|
|
6871
|
+
selectors: {
|
|
6872
|
+
light: [":root", "[data-ui-theme='light']"],
|
|
6873
|
+
dark: [".dark", "[data-ui-theme='dark']"]
|
|
6874
|
+
},
|
|
6875
|
+
overrideFile: "src/styles/ui-theme.css",
|
|
6876
|
+
rules: [
|
|
6877
|
+
"Import the package stylesheet before your project theme override stylesheet.",
|
|
6878
|
+
"Override tokens in one shared theme file instead of scattering colors across components.",
|
|
6879
|
+
"Use :root for the default light theme and .dark or [data-ui-theme='dark'] for dark theme.",
|
|
6880
|
+
"Only override tokens declared here. Do not patch component internals unless you are extending the library.",
|
|
6881
|
+
"For AI-generated screens, choose one theme source of truth and keep component code token-driven."
|
|
6882
|
+
],
|
|
6883
|
+
tokens: [
|
|
6884
|
+
{
|
|
6885
|
+
name: "--tw-background",
|
|
6886
|
+
description: "Base app background in HSL triplet format.",
|
|
6887
|
+
defaultLight: "0 0% 100%",
|
|
6888
|
+
defaultDark: "222.2 84% 4.9%",
|
|
6889
|
+
usedBy: ["Input", "Select", "Card", "Tabs", "global surface"]
|
|
6890
|
+
},
|
|
6891
|
+
{
|
|
6892
|
+
name: "--tw-foreground",
|
|
6893
|
+
description: "Primary text color in HSL triplet format.",
|
|
6894
|
+
defaultLight: "222.2 47.4% 11.2%",
|
|
6895
|
+
defaultDark: "210 40% 98%",
|
|
6896
|
+
usedBy: ["Button", "Input", "Card", "Typography"]
|
|
6897
|
+
},
|
|
6898
|
+
{
|
|
6899
|
+
name: "--tw-primary",
|
|
6900
|
+
description: "Primary brand color in HSL triplet format.",
|
|
6901
|
+
defaultLight: "221.2 83.2% 53.3%",
|
|
6902
|
+
defaultDark: "217.2 91.2% 59.8%",
|
|
6903
|
+
usedBy: ["Button", "focus rings", "brand emphasis"]
|
|
6904
|
+
},
|
|
6905
|
+
{
|
|
6906
|
+
name: "--tw-accent",
|
|
6907
|
+
description: "Accent color in HSL triplet format.",
|
|
6908
|
+
defaultLight: "199 89% 48%",
|
|
6909
|
+
defaultDark: "199 89% 48%",
|
|
6910
|
+
usedBy: ["Tabs", "checkbox accent", "highlight states"]
|
|
6911
|
+
},
|
|
6912
|
+
{
|
|
6913
|
+
name: "--tw-success",
|
|
6914
|
+
description: "Success state color in HSL triplet format.",
|
|
6915
|
+
defaultLight: "142.1 76.2% 36.3%",
|
|
6916
|
+
defaultDark: "142.1 70.6% 45.3%",
|
|
6917
|
+
usedBy: ["Alert", "confirm buttons", "status text"]
|
|
6918
|
+
},
|
|
6919
|
+
{
|
|
6920
|
+
name: "--tw-destructive",
|
|
6921
|
+
description: "Danger state color in HSL triplet format.",
|
|
6922
|
+
defaultLight: "0 84.2% 60.2%",
|
|
6923
|
+
defaultDark: "0 62.8% 30.6%",
|
|
6924
|
+
usedBy: ["Alert", "destructive buttons", "error states"]
|
|
6925
|
+
},
|
|
6926
|
+
{
|
|
6927
|
+
name: "--tw-border",
|
|
6928
|
+
description: "Border color in HSL triplet format.",
|
|
6929
|
+
defaultLight: "214.3 31.8% 91.4%",
|
|
6930
|
+
defaultDark: "217.2 32.6% 17.5%",
|
|
6931
|
+
usedBy: ["Input", "Select", "Card", "DataTable"]
|
|
6932
|
+
},
|
|
6933
|
+
{
|
|
6934
|
+
name: "--surface",
|
|
6935
|
+
description: "Default surface background as a CSS color.",
|
|
6936
|
+
defaultLight: "rgba(255, 255, 255, 0.92)",
|
|
6937
|
+
defaultDark: "rgba(15, 23, 42, 0.78)",
|
|
6938
|
+
usedBy: ["Tabs", "Pagination", "glass surfaces"]
|
|
6939
|
+
},
|
|
6940
|
+
{
|
|
6941
|
+
name: "--surface-strong",
|
|
6942
|
+
description: "Stronger elevated surface as a CSS color.",
|
|
6943
|
+
defaultLight: "rgba(241, 245, 249, 0.96)",
|
|
6944
|
+
defaultDark: "rgba(30, 41, 59, 0.92)",
|
|
6945
|
+
usedBy: ["Pagination hover", "raised surfaces"]
|
|
6946
|
+
},
|
|
6947
|
+
{
|
|
6948
|
+
name: "--grey",
|
|
6949
|
+
description: "Neutral table/header background as a CSS color.",
|
|
6950
|
+
defaultLight: "rgba(248, 250, 252, 0.96)",
|
|
6951
|
+
defaultDark: "rgba(30, 41, 59, 0.88)",
|
|
6952
|
+
usedBy: ["DataTable header"]
|
|
6953
|
+
},
|
|
6954
|
+
{
|
|
6955
|
+
name: "--grey-strong",
|
|
6956
|
+
description: "Hover background for neutral rows as a CSS color.",
|
|
6957
|
+
defaultLight: "rgba(241, 245, 249, 0.98)",
|
|
6958
|
+
defaultDark: "rgba(51, 65, 85, 0.92)",
|
|
6959
|
+
usedBy: ["DataTable row hover"]
|
|
6960
|
+
},
|
|
6961
|
+
{
|
|
6962
|
+
name: "--text",
|
|
6963
|
+
description: "Generic text color alias as a CSS color.",
|
|
6964
|
+
defaultLight: "hsl(var(--tw-foreground))",
|
|
6965
|
+
defaultDark: "hsl(var(--tw-foreground))",
|
|
6966
|
+
usedBy: ["Pagination", "legacy utility surfaces"]
|
|
6967
|
+
},
|
|
6968
|
+
{
|
|
6969
|
+
name: "--muted",
|
|
6970
|
+
description: "Generic muted text color alias as a CSS color.",
|
|
6971
|
+
defaultLight: "hsl(var(--tw-muted-foreground))",
|
|
6972
|
+
defaultDark: "hsl(var(--tw-muted-foreground))",
|
|
6973
|
+
usedBy: ["Pagination", "DataTable sort icon", "helper text"]
|
|
6974
|
+
},
|
|
6975
|
+
{
|
|
6976
|
+
name: "--accent",
|
|
6977
|
+
description: "Generic accent color alias as a CSS color.",
|
|
6978
|
+
defaultLight: "hsl(var(--tw-accent))",
|
|
6979
|
+
defaultDark: "hsl(var(--tw-accent))",
|
|
6980
|
+
usedBy: ["DataTable checkbox accent", "focus accents"]
|
|
6981
|
+
},
|
|
6982
|
+
{
|
|
6983
|
+
name: "--primary-grad-from",
|
|
6984
|
+
description: "Gradient start color in HSL triplet format.",
|
|
6985
|
+
defaultLight: "199 89% 48%",
|
|
6986
|
+
defaultDark: "198.6 88.7% 48.4%",
|
|
6987
|
+
usedBy: ["Button variant create"]
|
|
6988
|
+
},
|
|
6989
|
+
{
|
|
6990
|
+
name: "--primary-grad-to",
|
|
6991
|
+
description: "Gradient end color in HSL triplet format.",
|
|
6992
|
+
defaultLight: "221.2 83.2% 53.3%",
|
|
6993
|
+
defaultDark: "221.2 83.2% 53.3%",
|
|
6994
|
+
usedBy: ["Button variant create"]
|
|
6995
|
+
}
|
|
6996
|
+
],
|
|
6997
|
+
exampleCss: `:root {
|
|
6998
|
+
--tw-primary: 12 88% 56%;
|
|
6999
|
+
--tw-accent: 24 95% 52%;
|
|
7000
|
+
--primary-grad-from: 24 95% 52%;
|
|
7001
|
+
--primary-grad-to: 12 88% 56%;
|
|
7002
|
+
--surface: rgba(255, 248, 240, 0.92);
|
|
7003
|
+
}
|
|
7004
|
+
|
|
7005
|
+
.dark {
|
|
7006
|
+
--tw-primary: 18 100% 62%;
|
|
7007
|
+
--tw-accent: 35 100% 58%;
|
|
7008
|
+
--surface: rgba(24, 24, 27, 0.82);
|
|
7009
|
+
}`
|
|
7010
|
+
};
|
|
7011
|
+
var uiProjectAiRules = [
|
|
7012
|
+
"Use @lucasvu/scope-ui as the default UI library.",
|
|
7013
|
+
"Import @lucasvu/scope-ui/styles.css once at the app entry.",
|
|
7014
|
+
"Import the project override theme file after the package stylesheet.",
|
|
7015
|
+
"Read uiAiManifest to choose the correct component by intent before coding.",
|
|
7016
|
+
"Read uiThemeContract before changing colors, shadows, or theme behavior.",
|
|
7017
|
+
"Prefer root exports and avoid MainFe unless the task explicitly targets a legacy screen."
|
|
7018
|
+
];
|
|
7019
|
+
|
|
6538
7020
|
exports.Alert = Alert;
|
|
6539
7021
|
exports.ArgonSidebar = ArgonSidebar;
|
|
6540
7022
|
exports.AsyncCombobox = AsyncCombobox;
|
|
@@ -6549,7 +7031,9 @@ exports.CardFooter = CardFooter;
|
|
|
6549
7031
|
exports.CardHeader = CardHeader;
|
|
6550
7032
|
exports.CardTitle = CardTitle;
|
|
6551
7033
|
exports.Combobox = Combobox;
|
|
7034
|
+
exports.Control = FormControl;
|
|
6552
7035
|
exports.DataTable = DataTable;
|
|
7036
|
+
exports.Description = FormDescription;
|
|
6553
7037
|
exports.Field = FormField;
|
|
6554
7038
|
exports.Form = Form;
|
|
6555
7039
|
exports.FormControl = FormControl;
|
|
@@ -6559,9 +7043,12 @@ exports.FormItem = FormItem;
|
|
|
6559
7043
|
exports.FormLabel = FormLabel;
|
|
6560
7044
|
exports.FormMessage = FormMessage;
|
|
6561
7045
|
exports.Input = Input;
|
|
7046
|
+
exports.Item = FormItem;
|
|
7047
|
+
exports.Label = FormLabel;
|
|
6562
7048
|
exports.LineClampTooltip = LineClampTooltip;
|
|
6563
7049
|
exports.Loading = Loading;
|
|
6564
7050
|
exports.MainFe = main_fe_exports;
|
|
7051
|
+
exports.Message = FormMessage;
|
|
6565
7052
|
exports.MultiSelect = MultiSelect;
|
|
6566
7053
|
exports.NumericInput = NumericInput;
|
|
6567
7054
|
exports.OverflowTooltip = OverflowTooltip;
|
|
@@ -6579,9 +7066,13 @@ exports.TableCell = TableCell;
|
|
|
6579
7066
|
exports.TableHeader = TableHeader;
|
|
6580
7067
|
exports.TableRow = TableRow;
|
|
6581
7068
|
exports.Tabs = Tabs;
|
|
7069
|
+
exports.Textarea = Textarea;
|
|
6582
7070
|
exports.Tooltip = Tooltip;
|
|
6583
7071
|
exports.TruncatedText = TruncatedText;
|
|
6584
7072
|
exports.cn = cn;
|
|
6585
7073
|
exports.defaultPermissionChecker = defaultPermissionChecker;
|
|
6586
7074
|
exports.filterSidebarItems = filterSidebarItems;
|
|
6587
7075
|
exports.hasActiveDescendant = hasActiveDescendant;
|
|
7076
|
+
exports.uiAiManifest = uiAiManifest;
|
|
7077
|
+
exports.uiProjectAiRules = uiProjectAiRules;
|
|
7078
|
+
exports.uiThemeContract = uiThemeContract;
|