@ladder-ui/select 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -191
- package/dist/index.mjs +1 -179
- package/dist/select.css +1 -147
- package/dist/select.vars.css +1 -28
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,191 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
-
var react = require('react');
|
|
7
|
-
var reactDom = require('react-dom');
|
|
8
|
-
var core = require('@ladder-ui/core');
|
|
9
|
-
var primitives = require('@ladder-ui/primitives');
|
|
10
|
-
|
|
11
|
-
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
|
|
12
|
-
// ─── Icons ──────────────────────────────────────────────────────────────────
|
|
13
|
-
function ChevronDownIcon({ className, style }) {
|
|
14
|
-
return (jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className: className, style: style, children: jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) }));
|
|
15
|
-
}
|
|
16
|
-
function CheckIcon({ className }) {
|
|
17
|
-
return (jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className: className, children: jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" }) }));
|
|
18
|
-
}
|
|
19
|
-
// ─── Helper: Label Extraction ────────────────────────────────────────────────
|
|
20
|
-
function extractTextContent(children) {
|
|
21
|
-
if (typeof children === "string")
|
|
22
|
-
return children;
|
|
23
|
-
if (typeof children === "number")
|
|
24
|
-
return String(children);
|
|
25
|
-
if (Array.isArray(children))
|
|
26
|
-
return children.map(extractTextContent).join("");
|
|
27
|
-
if (react.isValidElement(children))
|
|
28
|
-
return extractTextContent(children.props.children);
|
|
29
|
-
return "";
|
|
30
|
-
}
|
|
31
|
-
function scanItemLabels(children, registry) {
|
|
32
|
-
react.Children.forEach(children, (child) => {
|
|
33
|
-
if (!react.isValidElement(child))
|
|
34
|
-
return;
|
|
35
|
-
// Check for SelectItem based on type or name
|
|
36
|
-
const type = child.type;
|
|
37
|
-
const dn = type.displayName || type.name;
|
|
38
|
-
if (dn === "SelectItem") {
|
|
39
|
-
const key = child.props.value ?? "";
|
|
40
|
-
const label = extractTextContent(child.props.children);
|
|
41
|
-
if (label)
|
|
42
|
-
registry.set(key, label);
|
|
43
|
-
}
|
|
44
|
-
if (child.props.children) {
|
|
45
|
-
scanItemLabels(child.props.children, registry);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
const SelectContext = react.createContext(null);
|
|
50
|
-
// ─── Variants ────────────────────────────────────────────────────────────────
|
|
51
|
-
const selectTriggerVariants = core.cva({
|
|
52
|
-
base: "lui-select-trigger",
|
|
53
|
-
variants: {
|
|
54
|
-
size: { sm: "lui-select-trigger--sm", md: "lui-select-trigger--md" },
|
|
55
|
-
status: { default: "", error: "lui-select-trigger--error" },
|
|
56
|
-
fullWidth: { true: "lui-select-trigger--full-width" },
|
|
57
|
-
},
|
|
58
|
-
defaultVariants: { size: "md", status: "default" },
|
|
59
|
-
});
|
|
60
|
-
function Select({ children, items, ...props }) {
|
|
61
|
-
const select = primitives.useSelect(props);
|
|
62
|
-
const labelsMap = react.useMemo(() => {
|
|
63
|
-
const map = new Map();
|
|
64
|
-
// 1. Scan children (Static JSX)
|
|
65
|
-
scanItemLabels(children, map);
|
|
66
|
-
// 2. Add explicit items (Dynamic/SDUI)
|
|
67
|
-
items?.forEach(item => map.set(item.value, item.label));
|
|
68
|
-
return map;
|
|
69
|
-
}, [children, items]);
|
|
70
|
-
const displayLabel = (select.value !== undefined ? labelsMap.get(select.value) : undefined) ?? "";
|
|
71
|
-
return (jsxRuntime.jsx(SelectContext, { value: { ...select, displayLabel }, children: children }));
|
|
72
|
-
}
|
|
73
|
-
Select.displayName = "Select";
|
|
74
|
-
const SelectTrigger = react.forwardRef(({ className, size, status, fullWidth, children, ...props }, ref) => {
|
|
75
|
-
const ctx = react.use(SelectContext);
|
|
76
|
-
if (!ctx)
|
|
77
|
-
return null;
|
|
78
|
-
const setRefs = (el) => {
|
|
79
|
-
ctx.triggerRef.current = el;
|
|
80
|
-
if (typeof ref === "function")
|
|
81
|
-
ref(el);
|
|
82
|
-
else if (ref)
|
|
83
|
-
ref.current = el;
|
|
84
|
-
};
|
|
85
|
-
return (jsxRuntime.jsxs("button", { ref: setRefs, type: "button", role: "combobox", id: ctx.triggerId, "aria-expanded": ctx.open, "aria-haspopup": "listbox", "aria-controls": ctx.open ? ctx.contentId : undefined, disabled: ctx.disabled, className: selectTriggerVariants({ size, status, fullWidth, className }), onClick: (e) => {
|
|
86
|
-
ctx.setOpen(!ctx.open);
|
|
87
|
-
props.onClick?.(e);
|
|
88
|
-
}, onKeyDown: (e) => {
|
|
89
|
-
if (e.key === "Escape" && ctx.open) {
|
|
90
|
-
e.preventDefault();
|
|
91
|
-
ctx.setOpen(false);
|
|
92
|
-
}
|
|
93
|
-
if ((e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && !ctx.open) {
|
|
94
|
-
e.preventDefault();
|
|
95
|
-
ctx.setOpen(true);
|
|
96
|
-
}
|
|
97
|
-
props.onKeyDown?.(e);
|
|
98
|
-
}, ...props, children: [children, jsxRuntime.jsx(ChevronDownIcon, { className: "lui-select-trigger__chevron" })] }));
|
|
99
|
-
});
|
|
100
|
-
SelectTrigger.displayName = "SelectTrigger";
|
|
101
|
-
const SelectValue = ({ placeholder, className }) => {
|
|
102
|
-
const ctx = react.use(SelectContext);
|
|
103
|
-
return (jsxRuntime.jsx("span", { className: core.concatClassNames("lui-select-value", className), "data-slot": "select-value", children: ctx?.displayLabel || placeholder }));
|
|
104
|
-
};
|
|
105
|
-
SelectValue.displayName = "SelectValue";
|
|
106
|
-
const SelectContent = react.forwardRef(({ children, className, ...props }, ref) => {
|
|
107
|
-
const ctx = react.use(SelectContext);
|
|
108
|
-
const contentRef = react.useRef(null);
|
|
109
|
-
const [coords, setCoords] = react.useState({ top: 0, left: 0, width: 0 });
|
|
110
|
-
const [isPositioned, setIsPositioned] = react.useState(false);
|
|
111
|
-
const { addRef } = primitives.useOutsideClick(() => ctx?.setOpen(false), ctx?.open);
|
|
112
|
-
// Two-pass positioning strategy
|
|
113
|
-
useIsomorphicLayoutEffect(() => {
|
|
114
|
-
if (!ctx?.open || !ctx.triggerRef.current || !contentRef.current) {
|
|
115
|
-
setIsPositioned(false);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const triggerRect = ctx.triggerRef.current.getBoundingClientRect();
|
|
119
|
-
const content = contentRef.current;
|
|
120
|
-
const contentHeight = content.offsetHeight;
|
|
121
|
-
const viewportHeight = window.innerHeight;
|
|
122
|
-
// Popper strategy: open below trigger
|
|
123
|
-
let top = triggerRect.bottom + window.scrollY + 4;
|
|
124
|
-
const left = triggerRect.left + window.scrollX;
|
|
125
|
-
// Flip if no space below
|
|
126
|
-
if (triggerRect.bottom + contentHeight + 8 > viewportHeight) {
|
|
127
|
-
top = triggerRect.top + window.scrollY - contentHeight - 4;
|
|
128
|
-
}
|
|
129
|
-
setCoords({ top, left, width: triggerRect.width });
|
|
130
|
-
setIsPositioned(true);
|
|
131
|
-
}, [ctx?.open]);
|
|
132
|
-
if (!ctx?.open)
|
|
133
|
-
return null;
|
|
134
|
-
return reactDom.createPortal(jsxRuntime.jsx("div", { ref: (node) => {
|
|
135
|
-
contentRef.current = node;
|
|
136
|
-
if (typeof ref === "function")
|
|
137
|
-
ref(node);
|
|
138
|
-
else if (ref)
|
|
139
|
-
ref.current = node;
|
|
140
|
-
if (node)
|
|
141
|
-
addRef({ current: node });
|
|
142
|
-
addRef(ctx.triggerRef);
|
|
143
|
-
}, id: ctx.contentId, role: "listbox", "aria-labelledby": ctx.triggerId, "data-slot": "select-content", className: core.concatClassNames("lui-select-content", className), style: {
|
|
144
|
-
position: "absolute",
|
|
145
|
-
top: coords.top,
|
|
146
|
-
left: coords.left,
|
|
147
|
-
width: coords.width,
|
|
148
|
-
minWidth: coords.width,
|
|
149
|
-
zIndex: 9999,
|
|
150
|
-
visibility: isPositioned ? "visible" : "hidden",
|
|
151
|
-
}, onKeyDown: (e) => {
|
|
152
|
-
if (e.key === "Escape") {
|
|
153
|
-
ctx.setOpen(false);
|
|
154
|
-
ctx.triggerRef.current?.focus();
|
|
155
|
-
}
|
|
156
|
-
props.onKeyDown?.(e);
|
|
157
|
-
}, ...props, children: jsxRuntime.jsx("div", { className: "lui-select-content__viewport", children: children }) }), document.body);
|
|
158
|
-
});
|
|
159
|
-
SelectContent.displayName = "SelectContent";
|
|
160
|
-
const SelectItem = react.forwardRef(({ value, children, disabled, className, ...props }, ref) => {
|
|
161
|
-
const ctx = react.use(SelectContext);
|
|
162
|
-
const isSelected = ctx?.value === value;
|
|
163
|
-
return (jsxRuntime.jsxs("div", { ref: ref, role: "option", "aria-selected": isSelected, "aria-disabled": disabled, className: core.concatClassNames("lui-select-item", isSelected && "lui-select-item--selected", disabled && "lui-select-item--disabled", className), onClick: (e) => {
|
|
164
|
-
if (!disabled) {
|
|
165
|
-
ctx?.onValueChange(value === null ? "" : value);
|
|
166
|
-
ctx?.setOpen(false);
|
|
167
|
-
}
|
|
168
|
-
props.onClick?.(e);
|
|
169
|
-
}, ...props, children: [jsxRuntime.jsx("span", { className: "lui-select-item__indicator", "aria-hidden": "true", children: isSelected && jsxRuntime.jsx(CheckIcon, { className: "lui-select-item__check" }) }), jsxRuntime.jsx("span", { className: "lui-select-item__text", children: children })] }));
|
|
170
|
-
});
|
|
171
|
-
SelectItem.displayName = "SelectItem";
|
|
172
|
-
const SelectGroup = react.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx("div", { ref: ref, role: "group", className: core.concatClassNames("lui-select-group", className), ...props })));
|
|
173
|
-
SelectGroup.displayName = "SelectGroup";
|
|
174
|
-
const SelectLabel = react.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx("div", { ref: ref, className: core.concatClassNames("lui-select-label", className), ...props })));
|
|
175
|
-
SelectLabel.displayName = "SelectLabel";
|
|
176
|
-
const SelectSeparator = react.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx("hr", { ref: ref, className: core.concatClassNames("lui-select-separator", className), ...props })));
|
|
177
|
-
SelectSeparator.displayName = "SelectSeparator";
|
|
178
|
-
const SelectScrollUpButton = react.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx("div", { ref: ref, className: core.concatClassNames("lui-select-scroll-button", className), "aria-hidden": "true", ...props, children: jsxRuntime.jsx(ChevronDownIcon, { className: "lui-select-scroll-button__icon", style: { transform: "rotate(180deg)" } }) })));
|
|
179
|
-
SelectScrollUpButton.displayName = "SelectScrollUpButton";
|
|
180
|
-
const SelectScrollDownButton = react.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx("div", { ref: ref, className: core.concatClassNames("lui-select-scroll-button", className), "aria-hidden": "true", ...props, children: jsxRuntime.jsx(ChevronDownIcon, { className: "lui-select-scroll-button__icon" }) })));
|
|
181
|
-
SelectScrollDownButton.displayName = "SelectScrollDownButton";
|
|
182
|
-
|
|
183
|
-
exports.Select = Select;
|
|
184
|
-
exports.SelectContent = SelectContent;
|
|
185
|
-
exports.SelectGroup = SelectGroup;
|
|
186
|
-
exports.SelectItem = SelectItem;
|
|
187
|
-
exports.SelectLabel = SelectLabel;
|
|
188
|
-
exports.SelectSeparator = SelectSeparator;
|
|
189
|
-
exports.SelectTrigger = SelectTrigger;
|
|
190
|
-
exports.SelectValue = SelectValue;
|
|
191
|
-
exports.default = Select;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),t=require("react"),s=require("react-dom"),l=require("@ladder-ui/core"),r=require("@ladder-ui/primitives");const a="undefined"!=typeof window?t.useLayoutEffect:t.useEffect;function n({className:t,style:s}){return e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",className:t,style:s,children:e.jsx("path",{d:"m6 9 6 6 6-6"})})}function i({className:t}){return e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.5,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",className:t,children:e.jsx("path",{d:"M20 6 9 17l-5-5"})})}function o(e){return"string"==typeof e?e:"number"==typeof e?String(e):Array.isArray(e)?e.map(o).join(""):t.isValidElement(e)?o(e.props.children):""}function c(e,s){t.Children.forEach(e,e=>{if(!t.isValidElement(e))return;const l=e.type;if("SelectItem"===(l.displayName||l.name)){const t=e.props.value??"",l=o(e.props.children);l&&s.set(t,l)}e.props.children&&c(e.props.children,s)})}const d=t.createContext(null),u=l.cva({base:"lui-select-trigger",variants:{size:{sm:"lui-select-trigger--sm",md:"lui-select-trigger--md"},status:{default:"",error:"lui-select-trigger--error"},fullWidth:{true:"lui-select-trigger--full-width"}},defaultVariants:{size:"md",status:"default"}});function p({children:s,items:l,...a}){const n=r.useSelect(a),i=t.useMemo(()=>{const e=new Map;return c(s,e),l?.forEach(t=>e.set(t.value,t.label)),e},[s,l]),o=(void 0!==n.value?i.get(n.value):void 0)??"";return e.jsx(d,{value:{...n,displayLabel:o},children:s})}p.displayName="Select";const m=t.forwardRef(({className:s,size:l,status:r,fullWidth:a,children:i,...o},c)=>{const p=t.use(d);return p?e.jsxs("button",{ref:e=>{p.triggerRef.current=e,"function"==typeof c?c(e):c&&(c.current=e)},type:"button",role:"combobox",id:p.triggerId,"aria-expanded":p.open,"aria-haspopup":"listbox","aria-controls":p.open?p.contentId:void 0,disabled:p.disabled,className:u({size:l,status:r,fullWidth:a,className:s}),onClick:e=>{p.setOpen(!p.open),o.onClick?.(e)},onKeyDown:e=>{"Escape"===e.key&&p.open&&(e.preventDefault(),p.setOpen(!1)),"ArrowDown"!==e.key&&"Enter"!==e.key&&" "!==e.key||p.open||(e.preventDefault(),p.setOpen(!0)),o.onKeyDown?.(e)},...o,children:[i,e.jsx(n,{className:"lui-select-trigger__chevron"})]}):null});m.displayName="SelectTrigger";const f=({placeholder:s,className:r})=>{const a=t.use(d);return e.jsx("span",{className:l.concatClassNames("lui-select-value",r),"data-slot":"select-value",children:a?.displayLabel||s})};f.displayName="SelectValue";const h=t.forwardRef(({children:n,className:i,...o},c)=>{const u=t.use(d),p=t.useRef(null),[m,f]=t.useState({top:0,left:0,width:0}),[h,N]=t.useState(!1),{addRef:g}=r.useOutsideClick(()=>u?.setOpen(!1),u?.open);return a(()=>{if(!u?.open||!u.triggerRef.current||!p.current)return void N(!1);const e=u.triggerRef.current.getBoundingClientRect(),t=p.current.offsetHeight,s=window.innerHeight;let l=e.bottom+window.scrollY+4;const r=e.left+window.scrollX;e.bottom+t+8>s&&(l=e.top+window.scrollY-t-4),f({top:l,left:r,width:e.width}),N(!0)},[u?.open]),u?.open?s.createPortal(e.jsx("div",{ref:e=>{p.current=e,"function"==typeof c?c(e):c&&(c.current=e),e&&g({current:e}),g(u.triggerRef)},id:u.contentId,role:"listbox","aria-labelledby":u.triggerId,"data-slot":"select-content",className:l.concatClassNames("lui-select-content",i),style:{position:"absolute",top:m.top,left:m.left,width:m.width,minWidth:m.width,zIndex:9999,visibility:h?"visible":"hidden"},onKeyDown:e=>{"Escape"===e.key&&(u.setOpen(!1),u.triggerRef.current?.focus()),o.onKeyDown?.(e)},...o,children:e.jsx("div",{className:"lui-select-content__viewport",children:n})}),document.body):null});h.displayName="SelectContent";const N=t.forwardRef(({value:s,children:r,disabled:a,className:n,...o},c)=>{const u=t.use(d),p=u?.value===s;return e.jsxs("div",{ref:c,role:"option","aria-selected":p,"aria-disabled":a,className:l.concatClassNames("lui-select-item",p&&"lui-select-item--selected",a&&"lui-select-item--disabled",n),onClick:e=>{a||(u?.onValueChange(null===s?"":s),u?.setOpen(!1)),o.onClick?.(e)},...o,children:[e.jsx("span",{className:"lui-select-item__indicator","aria-hidden":"true",children:p&&e.jsx(i,{className:"lui-select-item__check"})}),e.jsx("span",{className:"lui-select-item__text",children:r})]})});N.displayName="SelectItem";const g=t.forwardRef(({className:t,...s},r)=>e.jsx("div",{ref:r,role:"group",className:l.concatClassNames("lui-select-group",t),...s}));g.displayName="SelectGroup";const w=t.forwardRef(({className:t,...s},r)=>e.jsx("div",{ref:r,className:l.concatClassNames("lui-select-label",t),...s}));w.displayName="SelectLabel";const x=t.forwardRef(({className:t,...s},r)=>e.jsx("hr",{ref:r,className:l.concatClassNames("lui-select-separator",t),...s}));x.displayName="SelectSeparator",t.forwardRef(({className:t,...s},r)=>e.jsx("div",{ref:r,className:l.concatClassNames("lui-select-scroll-button",t),"aria-hidden":"true",...s,children:e.jsx(n,{className:"lui-select-scroll-button__icon",style:{transform:"rotate(180deg)"}})})).displayName="SelectScrollUpButton",t.forwardRef(({className:t,...s},r)=>e.jsx("div",{ref:r,className:l.concatClassNames("lui-select-scroll-button",t),"aria-hidden":"true",...s,children:e.jsx(n,{className:"lui-select-scroll-button__icon"})})).displayName="SelectScrollDownButton",exports.Select=p,exports.SelectContent=h,exports.SelectGroup=g,exports.SelectItem=N,exports.SelectLabel=w,exports.SelectSeparator=x,exports.SelectTrigger=m,exports.SelectValue=f,exports.default=p;
|
package/dist/index.mjs
CHANGED
|
@@ -1,179 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createContext, forwardRef, use, useRef, useState, useLayoutEffect, useEffect, useMemo, Children, isValidElement } from 'react';
|
|
3
|
-
import { createPortal } from 'react-dom';
|
|
4
|
-
import { cva, concatClassNames } from '@ladder-ui/core';
|
|
5
|
-
import { useOutsideClick, useSelect } from '@ladder-ui/primitives';
|
|
6
|
-
|
|
7
|
-
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
8
|
-
// ─── Icons ──────────────────────────────────────────────────────────────────
|
|
9
|
-
function ChevronDownIcon({ className, style }) {
|
|
10
|
-
return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className: className, style: style, children: jsx("path", { d: "m6 9 6 6 6-6" }) }));
|
|
11
|
-
}
|
|
12
|
-
function CheckIcon({ className }) {
|
|
13
|
-
return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className: className, children: jsx("path", { d: "M20 6 9 17l-5-5" }) }));
|
|
14
|
-
}
|
|
15
|
-
// ─── Helper: Label Extraction ────────────────────────────────────────────────
|
|
16
|
-
function extractTextContent(children) {
|
|
17
|
-
if (typeof children === "string")
|
|
18
|
-
return children;
|
|
19
|
-
if (typeof children === "number")
|
|
20
|
-
return String(children);
|
|
21
|
-
if (Array.isArray(children))
|
|
22
|
-
return children.map(extractTextContent).join("");
|
|
23
|
-
if (isValidElement(children))
|
|
24
|
-
return extractTextContent(children.props.children);
|
|
25
|
-
return "";
|
|
26
|
-
}
|
|
27
|
-
function scanItemLabels(children, registry) {
|
|
28
|
-
Children.forEach(children, (child) => {
|
|
29
|
-
if (!isValidElement(child))
|
|
30
|
-
return;
|
|
31
|
-
// Check for SelectItem based on type or name
|
|
32
|
-
const type = child.type;
|
|
33
|
-
const dn = type.displayName || type.name;
|
|
34
|
-
if (dn === "SelectItem") {
|
|
35
|
-
const key = child.props.value ?? "";
|
|
36
|
-
const label = extractTextContent(child.props.children);
|
|
37
|
-
if (label)
|
|
38
|
-
registry.set(key, label);
|
|
39
|
-
}
|
|
40
|
-
if (child.props.children) {
|
|
41
|
-
scanItemLabels(child.props.children, registry);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
const SelectContext = createContext(null);
|
|
46
|
-
// ─── Variants ────────────────────────────────────────────────────────────────
|
|
47
|
-
const selectTriggerVariants = cva({
|
|
48
|
-
base: "lui-select-trigger",
|
|
49
|
-
variants: {
|
|
50
|
-
size: { sm: "lui-select-trigger--sm", md: "lui-select-trigger--md" },
|
|
51
|
-
status: { default: "", error: "lui-select-trigger--error" },
|
|
52
|
-
fullWidth: { true: "lui-select-trigger--full-width" },
|
|
53
|
-
},
|
|
54
|
-
defaultVariants: { size: "md", status: "default" },
|
|
55
|
-
});
|
|
56
|
-
function Select({ children, items, ...props }) {
|
|
57
|
-
const select = useSelect(props);
|
|
58
|
-
const labelsMap = useMemo(() => {
|
|
59
|
-
const map = new Map();
|
|
60
|
-
// 1. Scan children (Static JSX)
|
|
61
|
-
scanItemLabels(children, map);
|
|
62
|
-
// 2. Add explicit items (Dynamic/SDUI)
|
|
63
|
-
items?.forEach(item => map.set(item.value, item.label));
|
|
64
|
-
return map;
|
|
65
|
-
}, [children, items]);
|
|
66
|
-
const displayLabel = (select.value !== undefined ? labelsMap.get(select.value) : undefined) ?? "";
|
|
67
|
-
return (jsx(SelectContext, { value: { ...select, displayLabel }, children: children }));
|
|
68
|
-
}
|
|
69
|
-
Select.displayName = "Select";
|
|
70
|
-
const SelectTrigger = forwardRef(({ className, size, status, fullWidth, children, ...props }, ref) => {
|
|
71
|
-
const ctx = use(SelectContext);
|
|
72
|
-
if (!ctx)
|
|
73
|
-
return null;
|
|
74
|
-
const setRefs = (el) => {
|
|
75
|
-
ctx.triggerRef.current = el;
|
|
76
|
-
if (typeof ref === "function")
|
|
77
|
-
ref(el);
|
|
78
|
-
else if (ref)
|
|
79
|
-
ref.current = el;
|
|
80
|
-
};
|
|
81
|
-
return (jsxs("button", { ref: setRefs, type: "button", role: "combobox", id: ctx.triggerId, "aria-expanded": ctx.open, "aria-haspopup": "listbox", "aria-controls": ctx.open ? ctx.contentId : undefined, disabled: ctx.disabled, className: selectTriggerVariants({ size, status, fullWidth, className }), onClick: (e) => {
|
|
82
|
-
ctx.setOpen(!ctx.open);
|
|
83
|
-
props.onClick?.(e);
|
|
84
|
-
}, onKeyDown: (e) => {
|
|
85
|
-
if (e.key === "Escape" && ctx.open) {
|
|
86
|
-
e.preventDefault();
|
|
87
|
-
ctx.setOpen(false);
|
|
88
|
-
}
|
|
89
|
-
if ((e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && !ctx.open) {
|
|
90
|
-
e.preventDefault();
|
|
91
|
-
ctx.setOpen(true);
|
|
92
|
-
}
|
|
93
|
-
props.onKeyDown?.(e);
|
|
94
|
-
}, ...props, children: [children, jsx(ChevronDownIcon, { className: "lui-select-trigger__chevron" })] }));
|
|
95
|
-
});
|
|
96
|
-
SelectTrigger.displayName = "SelectTrigger";
|
|
97
|
-
const SelectValue = ({ placeholder, className }) => {
|
|
98
|
-
const ctx = use(SelectContext);
|
|
99
|
-
return (jsx("span", { className: concatClassNames("lui-select-value", className), "data-slot": "select-value", children: ctx?.displayLabel || placeholder }));
|
|
100
|
-
};
|
|
101
|
-
SelectValue.displayName = "SelectValue";
|
|
102
|
-
const SelectContent = forwardRef(({ children, className, ...props }, ref) => {
|
|
103
|
-
const ctx = use(SelectContext);
|
|
104
|
-
const contentRef = useRef(null);
|
|
105
|
-
const [coords, setCoords] = useState({ top: 0, left: 0, width: 0 });
|
|
106
|
-
const [isPositioned, setIsPositioned] = useState(false);
|
|
107
|
-
const { addRef } = useOutsideClick(() => ctx?.setOpen(false), ctx?.open);
|
|
108
|
-
// Two-pass positioning strategy
|
|
109
|
-
useIsomorphicLayoutEffect(() => {
|
|
110
|
-
if (!ctx?.open || !ctx.triggerRef.current || !contentRef.current) {
|
|
111
|
-
setIsPositioned(false);
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
const triggerRect = ctx.triggerRef.current.getBoundingClientRect();
|
|
115
|
-
const content = contentRef.current;
|
|
116
|
-
const contentHeight = content.offsetHeight;
|
|
117
|
-
const viewportHeight = window.innerHeight;
|
|
118
|
-
// Popper strategy: open below trigger
|
|
119
|
-
let top = triggerRect.bottom + window.scrollY + 4;
|
|
120
|
-
const left = triggerRect.left + window.scrollX;
|
|
121
|
-
// Flip if no space below
|
|
122
|
-
if (triggerRect.bottom + contentHeight + 8 > viewportHeight) {
|
|
123
|
-
top = triggerRect.top + window.scrollY - contentHeight - 4;
|
|
124
|
-
}
|
|
125
|
-
setCoords({ top, left, width: triggerRect.width });
|
|
126
|
-
setIsPositioned(true);
|
|
127
|
-
}, [ctx?.open]);
|
|
128
|
-
if (!ctx?.open)
|
|
129
|
-
return null;
|
|
130
|
-
return createPortal(jsx("div", { ref: (node) => {
|
|
131
|
-
contentRef.current = node;
|
|
132
|
-
if (typeof ref === "function")
|
|
133
|
-
ref(node);
|
|
134
|
-
else if (ref)
|
|
135
|
-
ref.current = node;
|
|
136
|
-
if (node)
|
|
137
|
-
addRef({ current: node });
|
|
138
|
-
addRef(ctx.triggerRef);
|
|
139
|
-
}, id: ctx.contentId, role: "listbox", "aria-labelledby": ctx.triggerId, "data-slot": "select-content", className: concatClassNames("lui-select-content", className), style: {
|
|
140
|
-
position: "absolute",
|
|
141
|
-
top: coords.top,
|
|
142
|
-
left: coords.left,
|
|
143
|
-
width: coords.width,
|
|
144
|
-
minWidth: coords.width,
|
|
145
|
-
zIndex: 9999,
|
|
146
|
-
visibility: isPositioned ? "visible" : "hidden",
|
|
147
|
-
}, onKeyDown: (e) => {
|
|
148
|
-
if (e.key === "Escape") {
|
|
149
|
-
ctx.setOpen(false);
|
|
150
|
-
ctx.triggerRef.current?.focus();
|
|
151
|
-
}
|
|
152
|
-
props.onKeyDown?.(e);
|
|
153
|
-
}, ...props, children: jsx("div", { className: "lui-select-content__viewport", children: children }) }), document.body);
|
|
154
|
-
});
|
|
155
|
-
SelectContent.displayName = "SelectContent";
|
|
156
|
-
const SelectItem = forwardRef(({ value, children, disabled, className, ...props }, ref) => {
|
|
157
|
-
const ctx = use(SelectContext);
|
|
158
|
-
const isSelected = ctx?.value === value;
|
|
159
|
-
return (jsxs("div", { ref: ref, role: "option", "aria-selected": isSelected, "aria-disabled": disabled, className: concatClassNames("lui-select-item", isSelected && "lui-select-item--selected", disabled && "lui-select-item--disabled", className), onClick: (e) => {
|
|
160
|
-
if (!disabled) {
|
|
161
|
-
ctx?.onValueChange(value === null ? "" : value);
|
|
162
|
-
ctx?.setOpen(false);
|
|
163
|
-
}
|
|
164
|
-
props.onClick?.(e);
|
|
165
|
-
}, ...props, children: [jsx("span", { className: "lui-select-item__indicator", "aria-hidden": "true", children: isSelected && jsx(CheckIcon, { className: "lui-select-item__check" }) }), jsx("span", { className: "lui-select-item__text", children: children })] }));
|
|
166
|
-
});
|
|
167
|
-
SelectItem.displayName = "SelectItem";
|
|
168
|
-
const SelectGroup = forwardRef(({ className, ...props }, ref) => (jsx("div", { ref: ref, role: "group", className: concatClassNames("lui-select-group", className), ...props })));
|
|
169
|
-
SelectGroup.displayName = "SelectGroup";
|
|
170
|
-
const SelectLabel = forwardRef(({ className, ...props }, ref) => (jsx("div", { ref: ref, className: concatClassNames("lui-select-label", className), ...props })));
|
|
171
|
-
SelectLabel.displayName = "SelectLabel";
|
|
172
|
-
const SelectSeparator = forwardRef(({ className, ...props }, ref) => (jsx("hr", { ref: ref, className: concatClassNames("lui-select-separator", className), ...props })));
|
|
173
|
-
SelectSeparator.displayName = "SelectSeparator";
|
|
174
|
-
const SelectScrollUpButton = forwardRef(({ className, ...props }, ref) => (jsx("div", { ref: ref, className: concatClassNames("lui-select-scroll-button", className), "aria-hidden": "true", ...props, children: jsx(ChevronDownIcon, { className: "lui-select-scroll-button__icon", style: { transform: "rotate(180deg)" } }) })));
|
|
175
|
-
SelectScrollUpButton.displayName = "SelectScrollUpButton";
|
|
176
|
-
const SelectScrollDownButton = forwardRef(({ className, ...props }, ref) => (jsx("div", { ref: ref, className: concatClassNames("lui-select-scroll-button", className), "aria-hidden": "true", ...props, children: jsx(ChevronDownIcon, { className: "lui-select-scroll-button__icon" }) })));
|
|
177
|
-
SelectScrollDownButton.displayName = "SelectScrollDownButton";
|
|
178
|
-
|
|
179
|
-
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Select as default };
|
|
1
|
+
import{jsxs as e,jsx as t}from"react/jsx-runtime";import{createContext as l,forwardRef as r,use as s,useRef as i,useState as n,useLayoutEffect as a,useEffect as o,useMemo as c,Children as d,isValidElement as u}from"react";import{createPortal as p}from"react-dom";import{cva as m,concatClassNames as f}from"@ladder-ui/core";import{useOutsideClick as h,useSelect as g}from"@ladder-ui/primitives";const N="undefined"!=typeof window?a:o;function y({className:e,style:l}){return t("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",className:e,style:l,children:t("path",{d:"m6 9 6 6 6-6"})})}function w({className:e}){return t("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.5,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",className:e,children:t("path",{d:"M20 6 9 17l-5-5"})})}function v(e){return"string"==typeof e?e:"number"==typeof e?String(e):Array.isArray(e)?e.map(v).join(""):u(e)?v(e.props.children):""}function b(e,t){d.forEach(e,e=>{if(!u(e))return;const l=e.type;if("SelectItem"===(l.displayName||l.name)){const l=e.props.value??"",r=v(e.props.children);r&&t.set(l,r)}e.props.children&&b(e.props.children,t)})}const k=l(null),S=m({base:"lui-select-trigger",variants:{size:{sm:"lui-select-trigger--sm",md:"lui-select-trigger--md"},status:{default:"",error:"lui-select-trigger--error"},fullWidth:{true:"lui-select-trigger--full-width"}},defaultVariants:{size:"md",status:"default"}});function _({children:e,items:l,...r}){const s=g(r),i=c(()=>{const t=new Map;return b(e,t),l?.forEach(e=>t.set(e.value,e.label)),t},[e,l]),n=(void 0!==s.value?i.get(s.value):void 0)??"";return t(k,{value:{...s,displayLabel:n},children:e})}_.displayName="Select";const x=r(({className:l,size:r,status:i,fullWidth:n,children:a,...o},c)=>{const d=s(k);return d?e("button",{ref:e=>{d.triggerRef.current=e,"function"==typeof c?c(e):c&&(c.current=e)},type:"button",role:"combobox",id:d.triggerId,"aria-expanded":d.open,"aria-haspopup":"listbox","aria-controls":d.open?d.contentId:void 0,disabled:d.disabled,className:S({size:r,status:i,fullWidth:n,className:l}),onClick:e=>{d.setOpen(!d.open),o.onClick?.(e)},onKeyDown:e=>{"Escape"===e.key&&d.open&&(e.preventDefault(),d.setOpen(!1)),"ArrowDown"!==e.key&&"Enter"!==e.key&&" "!==e.key||d.open||(e.preventDefault(),d.setOpen(!0)),o.onKeyDown?.(e)},...o,children:[a,t(y,{className:"lui-select-trigger__chevron"})]}):null});x.displayName="SelectTrigger";const C=({placeholder:e,className:l})=>{const r=s(k);return t("span",{className:f("lui-select-value",l),"data-slot":"select-value",children:r?.displayLabel||e})};C.displayName="SelectValue";const D=r(({children:e,className:l,...r},a)=>{const o=s(k),c=i(null),[d,u]=n({top:0,left:0,width:0}),[m,g]=n(!1),{addRef:y}=h(()=>o?.setOpen(!1),o?.open);return N(()=>{if(!o?.open||!o.triggerRef.current||!c.current)return void g(!1);const e=o.triggerRef.current.getBoundingClientRect(),t=c.current.offsetHeight,l=window.innerHeight;let r=e.bottom+window.scrollY+4;const s=e.left+window.scrollX;e.bottom+t+8>l&&(r=e.top+window.scrollY-t-4),u({top:r,left:s,width:e.width}),g(!0)},[o?.open]),o?.open?p(t("div",{ref:e=>{c.current=e,"function"==typeof a?a(e):a&&(a.current=e),e&&y({current:e}),y(o.triggerRef)},id:o.contentId,role:"listbox","aria-labelledby":o.triggerId,"data-slot":"select-content",className:f("lui-select-content",l),style:{position:"absolute",top:d.top,left:d.left,width:d.width,minWidth:d.width,zIndex:9999,visibility:m?"visible":"hidden"},onKeyDown:e=>{"Escape"===e.key&&(o.setOpen(!1),o.triggerRef.current?.focus()),r.onKeyDown?.(e)},...r,children:t("div",{className:"lui-select-content__viewport",children:e})}),document.body):null});D.displayName="SelectContent";const I=r(({value:l,children:r,disabled:i,className:n,...a},o)=>{const c=s(k),d=c?.value===l;return e("div",{ref:o,role:"option","aria-selected":d,"aria-disabled":i,className:f("lui-select-item",d&&"lui-select-item--selected",i&&"lui-select-item--disabled",n),onClick:e=>{i||(c?.onValueChange(null===l?"":l),c?.setOpen(!1)),a.onClick?.(e)},...a,children:[t("span",{className:"lui-select-item__indicator","aria-hidden":"true",children:d&&t(w,{className:"lui-select-item__check"})}),t("span",{className:"lui-select-item__text",children:r})]})});I.displayName="SelectItem";const L=r(({className:e,...l},r)=>t("div",{ref:r,role:"group",className:f("lui-select-group",e),...l}));L.displayName="SelectGroup";const R=r(({className:e,...l},r)=>t("div",{ref:r,className:f("lui-select-label",e),...l}));R.displayName="SelectLabel";const O=r(({className:e,...l},r)=>t("hr",{ref:r,className:f("lui-select-separator",e),...l}));O.displayName="SelectSeparator",r(({className:e,...l},r)=>t("div",{ref:r,className:f("lui-select-scroll-button",e),"aria-hidden":"true",...l,children:t(y,{className:"lui-select-scroll-button__icon",style:{transform:"rotate(180deg)"}})})).displayName="SelectScrollUpButton",r(({className:e,...l},r)=>t("div",{ref:r,className:f("lui-select-scroll-button",e),"aria-hidden":"true",...l,children:t(y,{className:"lui-select-scroll-button__icon"})})).displayName="SelectScrollDownButton";export{_ as Select,D as SelectContent,L as SelectGroup,I as SelectItem,R as SelectLabel,O as SelectSeparator,x as SelectTrigger,C as SelectValue,_ as default};
|
package/dist/select.css
CHANGED
|
@@ -1,147 +1 @@
|
|
|
1
|
-
@charset "UTF-8";
|
|
2
|
-
@layer components {
|
|
3
|
-
.lui-select-trigger {
|
|
4
|
-
position: relative;
|
|
5
|
-
display: inline-flex;
|
|
6
|
-
align-items: center;
|
|
7
|
-
justify-content: space-between;
|
|
8
|
-
gap: 0.5rem;
|
|
9
|
-
width: fit-content;
|
|
10
|
-
height: var(--lui-select-trigger-height);
|
|
11
|
-
padding: var(--lui-select-trigger-py) var(--lui-select-trigger-px);
|
|
12
|
-
background-color: var(--lui-select-trigger-bg);
|
|
13
|
-
color: var(--lui-select-trigger-text);
|
|
14
|
-
border: 1px solid var(--lui-select-trigger-border);
|
|
15
|
-
border-radius: var(--lui-select-trigger-radius);
|
|
16
|
-
font-family: var(--lui-font-family);
|
|
17
|
-
font-size: 0.875rem;
|
|
18
|
-
line-height: 1.25;
|
|
19
|
-
white-space: nowrap;
|
|
20
|
-
text-align: left;
|
|
21
|
-
cursor: pointer;
|
|
22
|
-
transition: var(--lui-transition);
|
|
23
|
-
vertical-align: middle;
|
|
24
|
-
outline: none;
|
|
25
|
-
user-select: none;
|
|
26
|
-
}
|
|
27
|
-
.lui-select-trigger:focus-visible {
|
|
28
|
-
border-color: var(--lui-select-focus-border);
|
|
29
|
-
box-shadow: 0 0 0 2px var(--lui-bg-surface), 0 0 0 4px var(--lui-select-focus-ring-color);
|
|
30
|
-
}
|
|
31
|
-
.lui-select-trigger:disabled, .lui-select-trigger[aria-disabled=true] {
|
|
32
|
-
opacity: var(--lui-disabled-opacity);
|
|
33
|
-
cursor: var(--lui-disabled-cursor);
|
|
34
|
-
pointer-events: none;
|
|
35
|
-
}
|
|
36
|
-
.lui-select-trigger--sm {
|
|
37
|
-
height: var(--lui-select-trigger-height-sm);
|
|
38
|
-
font-size: 0.8125rem;
|
|
39
|
-
}
|
|
40
|
-
.lui-select-trigger--full-width {
|
|
41
|
-
width: 100%;
|
|
42
|
-
}
|
|
43
|
-
.lui-select-trigger__chevron {
|
|
44
|
-
width: 1rem;
|
|
45
|
-
height: 1rem;
|
|
46
|
-
opacity: 0.5;
|
|
47
|
-
flex-shrink: 0;
|
|
48
|
-
pointer-events: none;
|
|
49
|
-
}
|
|
50
|
-
.lui-select-value {
|
|
51
|
-
overflow: hidden;
|
|
52
|
-
text-overflow: ellipsis;
|
|
53
|
-
white-space: nowrap;
|
|
54
|
-
flex: 1;
|
|
55
|
-
min-width: 0;
|
|
56
|
-
}
|
|
57
|
-
.lui-select-value:empty::before {
|
|
58
|
-
content: "";
|
|
59
|
-
}
|
|
60
|
-
.lui-select-content {
|
|
61
|
-
background-color: var(--lui-select-content-bg);
|
|
62
|
-
border: 1px solid var(--lui-select-content-border);
|
|
63
|
-
border-radius: var(--lui-select-content-radius);
|
|
64
|
-
box-shadow: var(--lui-select-content-shadow);
|
|
65
|
-
overflow: hidden;
|
|
66
|
-
animation: lui-select-fade-in 0.12s ease-out;
|
|
67
|
-
}
|
|
68
|
-
.lui-select-content__viewport {
|
|
69
|
-
overflow-y: auto;
|
|
70
|
-
max-height: var(--lui-select-content-max-height);
|
|
71
|
-
overscroll-behavior: contain;
|
|
72
|
-
padding: 0.25rem;
|
|
73
|
-
scroll-padding-block: 0.25rem;
|
|
74
|
-
}
|
|
75
|
-
@keyframes lui-select-fade-in {
|
|
76
|
-
from {
|
|
77
|
-
opacity: 0;
|
|
78
|
-
transform: scale(0.97);
|
|
79
|
-
}
|
|
80
|
-
to {
|
|
81
|
-
opacity: 1;
|
|
82
|
-
transform: scale(1);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
.lui-select-label {
|
|
86
|
-
padding: 0.375rem 0.5rem 0.25rem;
|
|
87
|
-
font-size: 0.75rem;
|
|
88
|
-
font-weight: 500;
|
|
89
|
-
color: var(--lui-select-label-text);
|
|
90
|
-
user-select: none;
|
|
91
|
-
font-family: var(--lui-font-family);
|
|
92
|
-
}
|
|
93
|
-
.lui-select-item {
|
|
94
|
-
position: relative;
|
|
95
|
-
display: flex;
|
|
96
|
-
align-items: center;
|
|
97
|
-
gap: 0.375rem;
|
|
98
|
-
padding: var(--lui-select-item-py) var(--lui-select-item-px);
|
|
99
|
-
padding-right: calc(var(--lui-select-item-px) + var(--lui-select-item-indicator-size) + 0.375rem);
|
|
100
|
-
border-radius: var(--lui-select-item-radius);
|
|
101
|
-
font-size: 0.875rem;
|
|
102
|
-
color: var(--lui-select-item-text);
|
|
103
|
-
cursor: pointer;
|
|
104
|
-
user-select: none;
|
|
105
|
-
outline: none;
|
|
106
|
-
transition: background-color 0.1s ease, color 0.1s ease;
|
|
107
|
-
font-family: var(--lui-font-family);
|
|
108
|
-
}
|
|
109
|
-
.lui-select-item:hover:not(.lui-select-item--disabled) {
|
|
110
|
-
background-color: var(--lui-select-item-hover-bg);
|
|
111
|
-
color: var(--lui-select-item-hover-text);
|
|
112
|
-
}
|
|
113
|
-
.lui-select-item--selected {
|
|
114
|
-
color: var(--lui-select-item-selected-text);
|
|
115
|
-
}
|
|
116
|
-
.lui-select-item--disabled {
|
|
117
|
-
opacity: var(--lui-disabled-opacity);
|
|
118
|
-
cursor: not-allowed;
|
|
119
|
-
pointer-events: none;
|
|
120
|
-
}
|
|
121
|
-
.lui-select-item__indicator {
|
|
122
|
-
position: absolute;
|
|
123
|
-
right: var(--lui-select-item-px);
|
|
124
|
-
display: flex;
|
|
125
|
-
align-items: center;
|
|
126
|
-
justify-content: center;
|
|
127
|
-
width: var(--lui-select-item-indicator-size);
|
|
128
|
-
height: var(--lui-select-item-indicator-size);
|
|
129
|
-
flex-shrink: 0;
|
|
130
|
-
}
|
|
131
|
-
.lui-select-item__check {
|
|
132
|
-
width: 0.875rem;
|
|
133
|
-
height: 0.875rem;
|
|
134
|
-
color: var(--lui-select-item-selected-text);
|
|
135
|
-
}
|
|
136
|
-
.lui-select-item__text {
|
|
137
|
-
overflow: hidden;
|
|
138
|
-
text-overflow: ellipsis;
|
|
139
|
-
white-space: nowrap;
|
|
140
|
-
flex: 1;
|
|
141
|
-
}
|
|
142
|
-
.lui-select-separator {
|
|
143
|
-
border: none;
|
|
144
|
-
border-top: 1px solid var(--lui-select-separator-color);
|
|
145
|
-
margin: 0.25rem -0.25rem;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
1
|
+
@charset "UTF-8";@layer components{.lui-select-trigger{align-items:center;background-color:var(--lui-select-trigger-bg);border:1px solid var(--lui-select-trigger-border);border-radius:var(--lui-select-trigger-radius);color:var(--lui-select-trigger-text);cursor:pointer;display:inline-flex;font-family:var(--lui-font-family);font-size:.875rem;gap:.5rem;height:var(--lui-select-trigger-height);justify-content:space-between;line-height:1.25;outline:none;padding:var(--lui-select-trigger-py) var(--lui-select-trigger-px);position:relative;text-align:left;transition:var(--lui-transition);user-select:none;vertical-align:middle;white-space:nowrap;width:fit-content}.lui-select-trigger:focus-visible{border-color:var(--lui-select-focus-border);box-shadow:0 0 0 2px var(--lui-bg-surface),0 0 0 4px var(--lui-select-focus-ring-color)}.lui-select-trigger:disabled,.lui-select-trigger[aria-disabled=true]{cursor:var(--lui-disabled-cursor);opacity:var(--lui-disabled-opacity);pointer-events:none}.lui-select-trigger--sm{font-size:.8125rem;height:var(--lui-select-trigger-height-sm)}.lui-select-trigger--full-width{width:100%}.lui-select-trigger__chevron{flex-shrink:0;height:1rem;opacity:.5;pointer-events:none;width:1rem}.lui-select-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lui-select-value:empty:before{content:""}.lui-select-content{animation:lui-select-fade-in .12s ease-out;background-color:var(--lui-select-content-bg);border:1px solid var(--lui-select-content-border);border-radius:var(--lui-select-content-radius);box-shadow:var(--lui-select-content-shadow);overflow:hidden}.lui-select-content__viewport{max-height:var(--lui-select-content-max-height);overflow-y:auto;overscroll-behavior:contain;padding:.25rem;scroll-padding-block:.25rem}@keyframes lui-select-fade-in{0%{opacity:0;transform:scale(.97)}to{opacity:1;transform:scale(1)}}.lui-select-label{color:var(--lui-select-label-text);font-size:.75rem;font-weight:500;padding:.375rem .5rem .25rem}.lui-select-item,.lui-select-label{font-family:var(--lui-font-family);user-select:none}.lui-select-item{align-items:center;border-radius:var(--lui-select-item-radius);color:var(--lui-select-item-text);cursor:pointer;display:flex;font-size:.875rem;gap:.375rem;outline:none;padding:var(--lui-select-item-py) var(--lui-select-item-px);padding-right:calc(var(--lui-select-item-px) + var(--lui-select-item-indicator-size) + .375rem);position:relative;transition:background-color .1s ease,color .1s ease}.lui-select-item:hover:not(.lui-select-item--disabled){background-color:var(--lui-select-item-hover-bg);color:var(--lui-select-item-hover-text)}.lui-select-item--selected{color:var(--lui-select-item-selected-text)}.lui-select-item--disabled{cursor:not-allowed;opacity:var(--lui-disabled-opacity);pointer-events:none}.lui-select-item__indicator{align-items:center;display:flex;flex-shrink:0;height:var(--lui-select-item-indicator-size);justify-content:center;position:absolute;right:var(--lui-select-item-px);width:var(--lui-select-item-indicator-size)}.lui-select-item__check{color:var(--lui-select-item-selected-text);height:.875rem;width:.875rem}.lui-select-item__text{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lui-select-separator{border:none;border-top:1px solid var(--lui-select-separator-color);margin:.25rem -.25rem}}
|
package/dist/select.vars.css
CHANGED
|
@@ -1,28 +1 @@
|
|
|
1
|
-
:root
|
|
2
|
-
--lui-select-trigger-bg: var(--lui-bg-surface);
|
|
3
|
-
--lui-select-trigger-text: var(--lui-text-primary);
|
|
4
|
-
--lui-select-trigger-border: var(--lui-border-default);
|
|
5
|
-
--lui-select-trigger-radius: var(--lui-radius-sm);
|
|
6
|
-
--lui-select-trigger-height: 2.25rem;
|
|
7
|
-
--lui-select-trigger-height-sm: 2rem;
|
|
8
|
-
--lui-select-trigger-px: 0.75rem;
|
|
9
|
-
--lui-select-trigger-py: 0.5rem;
|
|
10
|
-
--lui-select-focus-border: var(--lui-bg-interactive);
|
|
11
|
-
--lui-select-focus-ring-color: color-mix(in srgb, var(--lui-bg-interactive) 40%, transparent);
|
|
12
|
-
--lui-select-content-bg: var(--lui-bg-surface);
|
|
13
|
-
--lui-select-content-border: var(--lui-border-default);
|
|
14
|
-
--lui-select-content-radius: var(--lui-radius-sm);
|
|
15
|
-
--lui-select-content-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.08);
|
|
16
|
-
--lui-select-content-max-height: 20rem;
|
|
17
|
-
--lui-select-item-text: var(--lui-text-primary);
|
|
18
|
-
--lui-select-item-hover-bg: color-mix(in srgb, var(--lui-bg-interactive) 10%, transparent);
|
|
19
|
-
--lui-select-item-hover-text: var(--lui-text-primary);
|
|
20
|
-
--lui-select-item-selected-text: var(--lui-bg-interactive);
|
|
21
|
-
--lui-select-item-focus-bg: color-mix(in srgb, var(--lui-bg-interactive) 10%, transparent);
|
|
22
|
-
--lui-select-item-radius: var(--lui-radius-sm);
|
|
23
|
-
--lui-select-item-px: 0.5rem;
|
|
24
|
-
--lui-select-item-py: 0.375rem;
|
|
25
|
-
--lui-select-item-indicator-size: 1rem;
|
|
26
|
-
--lui-select-label-text: color-mix(in srgb, var(--lui-text-primary) 60%, transparent);
|
|
27
|
-
--lui-select-separator-color: var(--lui-border-default);
|
|
28
|
-
}
|
|
1
|
+
:root{--lui-select-trigger-bg:var(--lui-bg-surface);--lui-select-trigger-text:var(--lui-text-primary);--lui-select-trigger-border:var(--lui-border-default);--lui-select-trigger-radius:var(--lui-radius-sm);--lui-select-trigger-height:2.25rem;--lui-select-trigger-height-sm:2rem;--lui-select-trigger-px:0.75rem;--lui-select-trigger-py:0.5rem;--lui-select-focus-border:var(--lui-bg-interactive);--lui-select-focus-ring-color:color-mix(in srgb,var(--lui-bg-interactive) 40%,transparent);--lui-select-content-bg:var(--lui-bg-surface);--lui-select-content-border:var(--lui-border-default);--lui-select-content-radius:var(--lui-radius-sm);--lui-select-content-shadow:0 4px 16px rgba(0,0,0,.12),0 1px 4px rgba(0,0,0,.08);--lui-select-content-max-height:20rem;--lui-select-item-text:var(--lui-text-primary);--lui-select-item-hover-bg:color-mix(in srgb,var(--lui-bg-interactive) 10%,transparent);--lui-select-item-hover-text:var(--lui-text-primary);--lui-select-item-selected-text:var(--lui-bg-interactive);--lui-select-item-focus-bg:color-mix(in srgb,var(--lui-bg-interactive) 10%,transparent);--lui-select-item-radius:var(--lui-radius-sm);--lui-select-item-px:0.5rem;--lui-select-item-py:0.375rem;--lui-select-item-indicator-size:1rem;--lui-select-label-text:color-mix(in srgb,var(--lui-text-primary) 60%,transparent);--lui-select-separator-color:var(--lui-border-default)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ladder-ui/select",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"sass": "^1.90.0",
|
|
27
27
|
"tslib": "^2.6.2",
|
|
28
28
|
"typescript": "^5.3.3",
|
|
29
|
-
"@ladder-ui/
|
|
30
|
-
"@ladder-ui/layout": "0.
|
|
31
|
-
"@ladder-ui/
|
|
29
|
+
"@ladder-ui/core": "0.5.0",
|
|
30
|
+
"@ladder-ui/layout": "0.5.0",
|
|
31
|
+
"@ladder-ui/primitives": "0.5.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@ladder-ui/core": ">=0.0.0",
|