@lerianstudio/sindarian-ui 1.2.0-beta.11 → 1.2.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ui/button/button.test.d.ts +2 -0
- package/dist/components/ui/button/button.test.d.ts.map +1 -0
- package/dist/components/ui/button/button.test.js +65 -0
- package/dist/components/ui/button/index.d.ts.map +1 -1
- package/dist/components/ui/button/index.js +1 -1
- package/dist/components/ui/dialog/styles.css +3 -3
- package/dist/components/ui/input/index.d.ts.map +1 -1
- package/dist/components/ui/input/index.js +4 -3
- package/dist/components/ui/input/input.test.d.ts +2 -0
- package/dist/components/ui/input/input.test.d.ts.map +1 -0
- package/dist/components/ui/input/input.test.js +52 -0
- package/dist/components/ui/input/styles.css +6 -2
- package/dist/globals.css +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.test.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/button/button.test.tsx"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
+
require("@testing-library/jest-dom");
|
|
5
|
+
const react_1 = require("@testing-library/react");
|
|
6
|
+
const _1 = require(".");
|
|
7
|
+
/**
|
|
8
|
+
* Regression coverage for `asChild`.
|
|
9
|
+
*
|
|
10
|
+
* Button always renders three children (the two icon slots evaluate to `false`
|
|
11
|
+
* when no `icon` is given). Without a `Slottable` marking the real child, Radix
|
|
12
|
+
* Slot >=1.3.0 cannot tell which of the three to merge onto and throws
|
|
13
|
+
* "Slot failed to slot onto its children" — which broke `<Button asChild>` for
|
|
14
|
+
* every consumer, icon or not.
|
|
15
|
+
*/
|
|
16
|
+
describe('Button asChild', () => {
|
|
17
|
+
it('renders the child element instead of a button, with no icon', () => {
|
|
18
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Button, { asChild: true, variant: "link", children: (0, jsx_runtime_1.jsx)("a", { href: "/somewhere", children: "Go somewhere" }) }));
|
|
19
|
+
const link = react_1.screen.getByRole('link', { name: 'Go somewhere' });
|
|
20
|
+
expect(link).toBeInTheDocument();
|
|
21
|
+
expect(link).toHaveAttribute('href', '/somewhere');
|
|
22
|
+
// asChild must NOT leave a wrapping <button> around the anchor.
|
|
23
|
+
expect(react_1.screen.queryByRole('button')).not.toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
it('merges the button classes onto the child element', () => {
|
|
26
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Button, { asChild: true, variant: "link", size: "small", className: "custom-class", children: (0, jsx_runtime_1.jsx)("a", { href: "/x", children: "Styled" }) }));
|
|
27
|
+
const link = react_1.screen.getByRole('link', { name: 'Styled' });
|
|
28
|
+
expect(link).toHaveClass('custom-class');
|
|
29
|
+
expect(link).toHaveAttribute('data-slot', 'button');
|
|
30
|
+
});
|
|
31
|
+
it('keeps a start icon alongside the slotted child', () => {
|
|
32
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Button, { asChild: true, icon: (0, jsx_runtime_1.jsx)("span", { "data-testid": "icon", children: "*" }), children: (0, jsx_runtime_1.jsx)("a", { href: "/x", children: "With icon" }) }));
|
|
33
|
+
const link = react_1.screen.getByRole('link', { name: /With icon/ });
|
|
34
|
+
expect(link).toBeInTheDocument();
|
|
35
|
+
// The icon renders inside the slotted element, not as a sibling of it.
|
|
36
|
+
expect(link).toContainElement(react_1.screen.getByTestId('icon'));
|
|
37
|
+
});
|
|
38
|
+
it('keeps an end icon alongside the slotted child', () => {
|
|
39
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Button, { asChild: true, icon: (0, jsx_runtime_1.jsx)("span", { "data-testid": "icon", children: "*" }), iconPlacement: "end", children: (0, jsx_runtime_1.jsx)("a", { href: "/x", children: "Trailing" }) }));
|
|
40
|
+
expect(react_1.screen.getByRole('link', { name: /Trailing/ })).toContainElement(react_1.screen.getByTestId('icon'));
|
|
41
|
+
});
|
|
42
|
+
it('accepts a child whose own content is multiple nodes', () => {
|
|
43
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Button, { asChild: true, variant: "link", children: (0, jsx_runtime_1.jsxs)("a", { href: "/x", children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", children: "\u21A9" }), "Back to list"] }) }));
|
|
44
|
+
expect(react_1.screen.getByRole('link', { name: 'Back to list' })).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('Button without asChild', () => {
|
|
48
|
+
it('still renders a native button (the Slottable path must be transparent)', () => {
|
|
49
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Button, { variant: "primary", children: "Click me" }));
|
|
50
|
+
const button = react_1.screen.getByRole('button', { name: 'Click me' });
|
|
51
|
+
expect(button.tagName).toBe('BUTTON');
|
|
52
|
+
expect(button).toHaveAttribute('data-slot', 'button');
|
|
53
|
+
});
|
|
54
|
+
it('still renders its icon', () => {
|
|
55
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Button, { icon: (0, jsx_runtime_1.jsx)("span", { "data-testid": "icon", children: "*" }), children: "Has an icon" }));
|
|
56
|
+
expect(react_1.screen.getByTestId('icon')).toBeInTheDocument();
|
|
57
|
+
expect(react_1.screen.getByRole('button', { name: /Has an icon/ })).toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
it('suppresses onClick when readOnly', () => {
|
|
60
|
+
const onClick = jest.fn();
|
|
61
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Button, { readOnly: true, onClick: onClick, children: "Read only" }));
|
|
62
|
+
react_1.screen.getByRole('button', { name: 'Read only' }).click();
|
|
63
|
+
expect(onClick).not.toHaveBeenCalled();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,QAAA,MAAM,cAAc;;;;8EA0BlB,CAAA;AAEF,QAAA,MAAM,YAAY;;;8EAgBhB,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GACtD,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,GAAG;IACF,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAAA;IAC3C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAEH,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAe,EACf,IAAI,EACJ,aAAuB,EACvB,SAAiB,EACjB,QAAgB,EAChB,OAAO,EACP,GAAG,KAAK,EACT,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,QAAA,MAAM,cAAc;;;;8EA0BlB,CAAA;AAEF,QAAA,MAAM,YAAY;;;8EAgBhB,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GACtD,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,GAAG;IACF,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAAA;IAC3C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAEH,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAe,EACf,IAAI,EACJ,aAAuB,EACvB,SAAiB,EACjB,QAAgB,EAChB,OAAO,EACP,GAAG,KAAK,EACT,EAAE,WAAW,qBAqCb;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -60,5 +60,5 @@ function Button({ className, variant, size, asChild = false, icon, iconPlacement
|
|
|
60
60
|
}
|
|
61
61
|
onClick?.(e);
|
|
62
62
|
};
|
|
63
|
-
return ((0, jsx_runtime_1.jsxs)(Comp, { className: (0, utils_1.cn)(buttonVariants({ variant, size, fullWidth }), className), "data-read-only": readOnly, "data-slot": "button", ...props, onClick: handleClick, children: [icon && iconPlacement === 'start' && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(iconVariants({ position: iconPlacement, size })), children: icon })), props.children, icon && iconPlacement !== 'start' && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(iconVariants({ position: iconPlacement, size })), children: icon }))] }));
|
|
63
|
+
return ((0, jsx_runtime_1.jsxs)(Comp, { className: (0, utils_1.cn)(buttonVariants({ variant, size, fullWidth }), className), "data-read-only": readOnly, "data-slot": "button", ...props, onClick: handleClick, children: [icon && iconPlacement === 'start' && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(iconVariants({ position: iconPlacement, size })), children: icon })), (0, jsx_runtime_1.jsx)(react_slot_1.Slottable, { children: props.children }), icon && iconPlacement !== 'start' && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)(iconVariants({ position: iconPlacement, size })), children: icon }))] }));
|
|
64
64
|
}
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
.dialog-content {
|
|
12
|
-
@apply bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed
|
|
12
|
+
@apply bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-8 border p-7 shadow-lg duration-200 sm:max-w-[425px] sm:rounded-lg;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.dialog-close {
|
|
16
|
-
@apply data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute
|
|
16
|
+
@apply data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 disabled:pointer-events-none;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
.dialog-header {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
.dialog-title {
|
|
28
|
-
@apply text-dialog-title-text text-lg font-bold
|
|
28
|
+
@apply text-dialog-title-text text-lg leading-none font-bold tracking-tight;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
.dialog-description {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/input/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/input/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,EAAO,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,QAAA,MAAM,aAAa;;;8EAejB,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,IAAI,CAC3B,YAAY,CAAC,OAAO,aAAa,CAAC,EAClC,gBAAgB,GAAG,cAAc,CAClC,GACC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG;IAC9B,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC9B,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;CAC1B,CAAA;AAEH,wBAAgB,KAAK,CAAC,EACpB,SAAS,EACT,cAAc,EACd,YAAY,EACZ,OAAO,EACP,MAAM,EACN,OAAO,EACP,GAAG,EACH,GAAG,KAAK,EACT,EAAE,UAAU,qBAyEZ;AAED,cAAc,aAAa,CAAA"}
|
|
@@ -40,7 +40,6 @@ exports.Input = Input;
|
|
|
40
40
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
41
41
|
const React = __importStar(require("react"));
|
|
42
42
|
const utils_1 = require("../../../lib/utils");
|
|
43
|
-
const form_1 = require("../../../components/ui/form");
|
|
44
43
|
const class_variance_authority_1 = require("class-variance-authority");
|
|
45
44
|
const inputVariants = (0, class_variance_authority_1.cva)('input-base input-disabled input-read-only', {
|
|
46
45
|
variants: {
|
|
@@ -59,7 +58,9 @@ const inputVariants = (0, class_variance_authority_1.cva)('input-base input-disa
|
|
|
59
58
|
}
|
|
60
59
|
});
|
|
61
60
|
function Input({ className, startAdornment, endAdornment, onFocus, onBlur, onClick, ref, ...props }) {
|
|
62
|
-
|
|
61
|
+
// Fallback id so a standalone Input is still labelable. Inside a form,
|
|
62
|
+
// FormControl injects its own id through `props` below and overrides this.
|
|
63
|
+
const generatedId = React.useId();
|
|
63
64
|
const [focus, setFocus] = React.useState(false);
|
|
64
65
|
const inputRef = React.useRef(null);
|
|
65
66
|
React.useImperativeHandle(ref, () => ({
|
|
@@ -90,7 +91,7 @@ function Input({ className, startAdornment, endAdornment, onFocus, onBlur, onCli
|
|
|
90
91
|
setFocus(false);
|
|
91
92
|
onBlur?.(e);
|
|
92
93
|
};
|
|
93
|
-
return ((0, jsx_runtime_1.jsxs)("div", { "data-slot": "input-wrapper", className: (0, utils_1.cn)('input-wrapper input-wrapper-focus'), "data-focus": focus, onClick: handleWrapperClick, children: [startAdornment, (0, jsx_runtime_1.jsx)("input", { ref: inputRef, id:
|
|
94
|
+
return ((0, jsx_runtime_1.jsxs)("div", { "data-slot": "input-wrapper", className: (0, utils_1.cn)('input-wrapper input-wrapper-focus'), "data-focus": focus, onClick: handleWrapperClick, children: [startAdornment, (0, jsx_runtime_1.jsx)("input", { ref: inputRef, id: generatedId, "data-slot": "input", className: (0, utils_1.cn)(inputVariants({
|
|
94
95
|
startAdornment: !!startAdornment,
|
|
95
96
|
endAdornment: !!endAdornment
|
|
96
97
|
}), className), onFocus: handleFocus, onBlur: handleBlur, ...props }), endAdornment] }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.test.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/input/input.test.tsx"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
+
require("@testing-library/jest-dom");
|
|
5
|
+
const react_1 = require("@testing-library/react");
|
|
6
|
+
const react_hook_form_1 = require("react-hook-form");
|
|
7
|
+
const _1 = require(".");
|
|
8
|
+
const form_1 = require("../form");
|
|
9
|
+
/**
|
|
10
|
+
* Regression coverage for standalone use.
|
|
11
|
+
*
|
|
12
|
+
* `Input` is a primitive with two callers: `InputField`, which wraps it in
|
|
13
|
+
* `FormField`/`FormItem`, and plain standalone use such as a search box. It
|
|
14
|
+
* used to call `useFormField`, which destructures `useFormContext()` — null
|
|
15
|
+
* with no provider above — so every standalone `<Input />` threw "Cannot
|
|
16
|
+
* destructure property 'getFieldState' of useFormContext(...) as it is null".
|
|
17
|
+
*
|
|
18
|
+
* It now reads no form context at all: a local `useId` covers the standalone
|
|
19
|
+
* case, and inside a form `FormControl`'s Slot injects the real id as a prop.
|
|
20
|
+
*/
|
|
21
|
+
describe('Input outside a form', () => {
|
|
22
|
+
it('renders with no react-hook-form provider', () => {
|
|
23
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Input, { placeholder: "Search permissions by name..." }));
|
|
24
|
+
expect(react_1.screen.getByPlaceholderText('Search permissions by name...')).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
it('still gets an id so a label can be associated with it', () => {
|
|
27
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Input, { "aria-label": "Search" }));
|
|
28
|
+
expect(react_1.screen.getByRole('textbox', { name: 'Search' })).toHaveAttribute('id');
|
|
29
|
+
});
|
|
30
|
+
it('keeps value/onChange behaviour intact', () => {
|
|
31
|
+
const onChange = jest.fn();
|
|
32
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(_1.Input, { value: "abc", onChange: onChange, "aria-label": "Search" }));
|
|
33
|
+
const input = react_1.screen.getByRole('textbox', { name: 'Search' });
|
|
34
|
+
expect(input).toHaveValue('abc');
|
|
35
|
+
react_1.fireEvent.change(input, { target: { value: 'abcd' } });
|
|
36
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
37
|
+
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ target: input }));
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
function FormHarness() {
|
|
41
|
+
const form = (0, react_hook_form_1.useForm)({ defaultValues: { email: 'ada@example.com' } });
|
|
42
|
+
return ((0, jsx_runtime_1.jsx)(form_1.Form, { ...form, children: (0, jsx_runtime_1.jsx)(form_1.FormField, { control: form.control, name: "email", render: ({ field }) => ((0, jsx_runtime_1.jsxs)(form_1.FormItem, { children: [(0, jsx_runtime_1.jsx)(form_1.FormLabel, { children: "E-mail" }), (0, jsx_runtime_1.jsx)(form_1.FormControl, { children: (0, jsx_runtime_1.jsx)(_1.Input, { ...field }) })] })) }) }));
|
|
43
|
+
}
|
|
44
|
+
describe('Input inside a form', () => {
|
|
45
|
+
it('is still wired to its FormItem id, so the label points at it', () => {
|
|
46
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(FormHarness, {}));
|
|
47
|
+
const input = react_1.screen.getByLabelText('E-mail');
|
|
48
|
+
expect(input).toHaveValue('ada@example.com');
|
|
49
|
+
// The id must come from FormItem's context, not the standalone fallback.
|
|
50
|
+
expect(input.getAttribute('id')).toMatch(/-form-item$/);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
--spacing-input-wrapper-p: calc(var(--spacing) * 2);
|
|
4
4
|
--spacing-input-px: calc(var(--spacing) * 4);
|
|
5
5
|
--color-input-foreground: var(--color-foreground);
|
|
6
|
-
--color-input-placeholder: var(--
|
|
6
|
+
--color-input-placeholder: hsl(var(--input-placeholder));
|
|
7
7
|
--color-input-border: var(--color-shadcn-400);
|
|
8
8
|
|
|
9
9
|
--color-input-adornment: var(--color-container-text);
|
|
@@ -24,8 +24,12 @@
|
|
|
24
24
|
@apply border-ring;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/* Don't give the placeholder its own size or weight. At a smaller size it
|
|
28
|
+
still shares the input's baseline, so it rode ~0.75px below the value and
|
|
29
|
+
the text jumped the moment you typed; font-medium gave the hint the same
|
|
30
|
+
presence as the label naming the field. */
|
|
27
31
|
.input-base {
|
|
28
|
-
@apply px-input-px text-input-foreground placeholder:text-input-placeholder h-full min-h-0 flex-1 border-none bg-transparent outline-none
|
|
32
|
+
@apply px-input-px text-input-foreground placeholder:text-input-placeholder h-full min-h-0 flex-1 border-none bg-transparent outline-none focus:ring-0 focus:ring-offset-0;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
.input-disabled {
|
package/dist/globals.css
CHANGED
|
@@ -228,6 +228,10 @@
|
|
|
228
228
|
--destructive-foreground: 0 0% 100%; /* white */
|
|
229
229
|
--border: 240 5% 90%; /* base/200 = #E4E4E7 */
|
|
230
230
|
--input: 0 0% 100%; /* base/white */
|
|
231
|
+
/* One step lighter than --muted-foreground, which is also the label colour:
|
|
232
|
+
a placeholder that matches its own label has no hierarchy left to give.
|
|
233
|
+
Still 4.4:1 on the shadcn-100 field, so it stays legible as a hint. */
|
|
234
|
+
--input-placeholder: 240 4% 46%; /* base/500 = #71717A */
|
|
231
235
|
--ring: 240 5% 65%; /* focus ring */
|
|
232
236
|
--radius: 0.5rem;
|
|
233
237
|
|
|
@@ -292,6 +296,10 @@
|
|
|
292
296
|
--popover-foreground: 240 5% 96%; /* base/100 = #F4F4F5 */
|
|
293
297
|
--border: 240 5% 34%; /* base/600 = #52525B */
|
|
294
298
|
--input: 240 4% 16%; /* base/800 = #27272A */
|
|
299
|
+
/* Held at base/400 rather than stepped down with the light theme: on the
|
|
300
|
+
dark field that is already only 5.8:1, and going lighter here means
|
|
301
|
+
darker, which would push the hint under the AA floor. */
|
|
302
|
+
--input-placeholder: 240 5% 65%; /* base/400 = #A1A1AA */
|
|
295
303
|
--primary: 240 5% 96%; /* base/100 = #F4F4F5 */
|
|
296
304
|
--primary-foreground: 240 4% 16%; /* base/800 = #27272A */
|
|
297
305
|
--secondary: 240 4% 16%; /* base/800 = #27272A */
|