@satellatickets/ui 0.2.0 → 0.3.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/README.md +2 -2
- package/dist/native/index.d.ts +1 -1
- package/dist/native/index.js +1 -1
- package/dist/web/index.d.ts +8 -5
- package/dist/web/index.js +248 -38
- package/dist/web/styles.css +82 -8
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Requiere `react-dom >=19.0`. Importa los estilos **una vez**, en la entrada de l
|
|
|
35
35
|
import '@satellatickets/ui/styles.css';
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
Es un CSS estático, sin runtime de estilos: funciona con SSR
|
|
38
|
+
Es un CSS estático, sin runtime de estilos: funciona con SSR, y cambiar de tema no re-renderiza nada. En Next.js, los componentes se importan directamente desde una página o un layout, sin envolverlos: el paquete ya lleva `"use client"`.
|
|
39
39
|
|
|
40
40
|
### React Native
|
|
41
41
|
|
|
@@ -51,7 +51,7 @@ No hay nada más que configurar: Metro resuelve la versión nativa del paquete.
|
|
|
51
51
|
|
|
52
52
|
### Fuentes
|
|
53
53
|
|
|
54
|
-
La librería nombra las familias de Satella (Unbounded, Hanken Grotesk e IBM Plex Mono) pero no las empaqueta: las carga cada app, con `
|
|
54
|
+
La librería nombra las familias de Satella (Unbounded, Hanken Grotesk e IBM Plex Mono) pero no las empaqueta: las carga cada app, con `@fontsource` o un `<link>` en web y con `expo-font` en nativo. Si una fuente no está cargada, se usa la del sistema.
|
|
55
55
|
|
|
56
56
|
## Tema y marca
|
|
57
57
|
|
package/dist/native/index.d.ts
CHANGED
|
@@ -189,7 +189,7 @@ interface SelectNativeProps extends SelectProps$1 {
|
|
|
189
189
|
//#endregion
|
|
190
190
|
//#region src/select/Select.native.d.ts
|
|
191
191
|
/**
|
|
192
|
-
* Un disparador con aspecto de `Input` que abre una lista modal (ADR-
|
|
192
|
+
* Un disparador con aspecto de `Input` que abre una lista modal (ADR-042). React
|
|
193
193
|
* Native no trae ningún selector, y así `Select` no añade dependencias.
|
|
194
194
|
*/
|
|
195
195
|
export declare function Select({ options, value, defaultValue, onValueChange, placeholder, size, disabled, invalid, required, accessibilityLabel, style, testID, ref }: SelectNativeProps): import("react").JSX.Element;
|
package/dist/native/index.js
CHANGED
|
@@ -1536,7 +1536,7 @@ const styles$6 = StyleSheet.create({
|
|
|
1536
1536
|
}
|
|
1537
1537
|
});
|
|
1538
1538
|
/**
|
|
1539
|
-
* Un disparador con aspecto de `Input` que abre una lista modal (ADR-
|
|
1539
|
+
* Un disparador con aspecto de `Input` que abre una lista modal (ADR-042). React
|
|
1540
1540
|
* Native no trae ningún selector, y así `Select` no añade dependencias.
|
|
1541
1541
|
*/
|
|
1542
1542
|
function Select({ options, value, defaultValue, onValueChange, placeholder, size = "md", disabled, invalid, required, accessibilityLabel, style, testID, ref }) {
|
package/dist/web/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
import { AlertProps, AlertProps as AlertProps$1, BadgeProps, BadgeProps as BadgeProps$1, BoxProps, BoxProps as BoxProps$1, ButtonProps as ButtonProps$1, CardProps, CardProps as CardProps$1, CheckboxProps, CheckboxProps as CheckboxProps$1, ColorScheme, DividerProps, DividerProps as DividerProps$1, FormFieldProps, FormFieldProps as FormFieldProps$1, IconButtonProps as IconButtonProps$1, IconProps as IconProps$1, InputProps as InputProps$1, LinkPressEvent, LinkProps, LinkProps as LinkProps$1, ModalProps, ModalProps as ModalProps$1, SelectOption, SelectProps, SelectProps as SelectProps$1, SheetProps, SkeletonProps, SkeletonProps as SkeletonProps$1, SpinnerProps, SpinnerProps as SpinnerProps$1, StackProps, StackProps as StackProps$1, SwitchProps, SwitchProps as SwitchProps$1, TabItem as TabItem$1, TabsProps as TabsProps$1, TextAreaProps, TextAreaProps as TextAreaProps$1, TextProps, TextProps as TextProps$1, ThemeMode, ToastAction, ToastApi, ToastOptions, UIProviderProps, UIProviderProps as UIProviderProps$1, useBrand, useColorScheme, useTheme, useToast } from "@satellatickets/core";
|
|
2
3
|
import { CSSProperties, Ref } from "react";
|
|
3
4
|
import "react-native";
|
|
@@ -181,20 +182,22 @@ export declare function Modal(props: ModalWebProps): import("react").JSX.Element
|
|
|
181
182
|
//#region src/select/Select.types.d.ts
|
|
182
183
|
/** Extensión solo web del contrato (ADR-009): atributos de formulario y escape hatches. */
|
|
183
184
|
interface SelectWebProps extends SelectProps$1 {
|
|
184
|
-
/** `id` del
|
|
185
|
+
/** `id` del botón que abre la lista. Dentro de un `FormField` no hace falta: lo pone él. */
|
|
185
186
|
id?: string | undefined;
|
|
186
187
|
/** Nombre con el que viaja en un `<form>`. */
|
|
187
188
|
name?: string | undefined;
|
|
188
|
-
/** Se aplican a la caja del campo, no al
|
|
189
|
+
/** Se aplican a la caja del campo, no al botón. */
|
|
189
190
|
className?: string | undefined;
|
|
190
191
|
style?: CSSProperties | undefined;
|
|
191
|
-
|
|
192
|
+
/** El botón que abre la lista (ADR-042). */
|
|
193
|
+
ref?: Ref<HTMLButtonElement> | undefined;
|
|
192
194
|
}
|
|
193
195
|
//#endregion
|
|
194
196
|
//#region src/select/Select.web.d.ts
|
|
195
197
|
/**
|
|
196
|
-
* Un
|
|
197
|
-
*
|
|
198
|
+
* Un botón que abre una lista propia (ADR-042). El foco no sale del botón: la opción
|
|
199
|
+
* resaltada se comunica con `aria-activedescendant`, y la lista se pinta en la capa
|
|
200
|
+
* superior del navegador, por encima de todo y sin que la recorte ningún contenedor.
|
|
198
201
|
*/
|
|
199
202
|
export declare function Select({ options, value, defaultValue, onValueChange, placeholder, size, disabled, invalid, required, accessibilityLabel, id, name, className, style, testID, ref }: SelectWebProps): import("react").JSX.Element;
|
|
200
203
|
//#endregion
|
package/dist/web/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { FormFieldContext, ToastContext, UIContext, buttonIconSize, createFormFieldValue, createToastStore, createUIContextValue, findOptionByText, firstEnabledTab, getOptionInDirection, getTabInDirection, iconButtonIconSize, iconSizePx, inputIconSize, isFeedbackTone, textVariantStyles, useBrand, useButton, useColorScheme, useControllableState, useFormFieldControl, useLink, useTheme, useToast } from "@satellatickets/core";
|
|
2
3
|
import { cssVariables } from "@satellatickets/tokens";
|
|
3
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
import { useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5
|
+
import { useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5
6
|
//#region src/_internal/cx.ts
|
|
6
7
|
/** Une clases CSS ignorando valores falsos. */
|
|
7
8
|
function cx(...parts) {
|
|
@@ -1084,13 +1085,19 @@ function Modal(props) {
|
|
|
1084
1085
|
//#endregion
|
|
1085
1086
|
//#region src/select/Select.module.css
|
|
1086
1087
|
var Select_module_default = {
|
|
1088
|
+
"active": "sui-active-Rxx4wG",
|
|
1087
1089
|
"chevron": "sui-chevron-Rxx4wG",
|
|
1090
|
+
"disabled": "sui-disabled-Rxx4wG",
|
|
1091
|
+
"focused": "sui-focused-Rxx4wG",
|
|
1092
|
+
"label": "sui-label-Rxx4wG",
|
|
1088
1093
|
"lg": "sui-lg-Rxx4wG",
|
|
1094
|
+
"list": "sui-list-Rxx4wG",
|
|
1089
1095
|
"md": "sui-md-Rxx4wG",
|
|
1096
|
+
"option": "sui-option-Rxx4wG",
|
|
1090
1097
|
"placeholder": "sui-placeholder-Rxx4wG",
|
|
1091
1098
|
"root": "sui-root-Rxx4wG",
|
|
1092
|
-
"
|
|
1093
|
-
"
|
|
1099
|
+
"sm": "sui-sm-Rxx4wG",
|
|
1100
|
+
"trigger": "sui-trigger-Rxx4wG"
|
|
1094
1101
|
};
|
|
1095
1102
|
//#endregion
|
|
1096
1103
|
//#region src/select/Select.web.tsx
|
|
@@ -1099,57 +1106,260 @@ const sizeClass = {
|
|
|
1099
1106
|
md: Select_module_default.md,
|
|
1100
1107
|
lg: Select_module_default.lg
|
|
1101
1108
|
};
|
|
1109
|
+
const keyDirection$1 = {
|
|
1110
|
+
ArrowDown: "next",
|
|
1111
|
+
ArrowUp: "previous",
|
|
1112
|
+
Home: "first",
|
|
1113
|
+
End: "last",
|
|
1114
|
+
PageDown: "nextPage",
|
|
1115
|
+
PageUp: "previousPage"
|
|
1116
|
+
};
|
|
1117
|
+
/** Pasado este tiempo sin escribir, la siguiente letra empieza una búsqueda nueva. */
|
|
1118
|
+
const SEARCH_TIMEOUT_MS = 500;
|
|
1119
|
+
/** Lo escrito para buscar una opción y el momento de la última letra. */
|
|
1120
|
+
const NO_SEARCH = {
|
|
1121
|
+
text: "",
|
|
1122
|
+
at: Number.NEGATIVE_INFINITY
|
|
1123
|
+
};
|
|
1102
1124
|
/**
|
|
1103
|
-
* Un
|
|
1104
|
-
*
|
|
1125
|
+
* Un botón que abre una lista propia (ADR-042). El foco no sale del botón: la opción
|
|
1126
|
+
* resaltada se comunica con `aria-activedescendant`, y la lista se pinta en la capa
|
|
1127
|
+
* superior del navegador, por encima de todo y sin que la recorte ningún contenedor.
|
|
1105
1128
|
*/
|
|
1106
1129
|
function Select({ options, value, defaultValue, onValueChange, placeholder, size = "md", disabled, invalid, required, accessibilityLabel, id, name, className, style, testID, ref }) {
|
|
1107
1130
|
const control = useFormFieldControl({
|
|
1108
1131
|
id,
|
|
1109
1132
|
invalid,
|
|
1110
1133
|
disabled,
|
|
1111
|
-
required
|
|
1134
|
+
required,
|
|
1135
|
+
accessibilityLabel
|
|
1112
1136
|
});
|
|
1113
1137
|
const [current, setCurrent] = useControllableState({
|
|
1114
1138
|
value,
|
|
1115
1139
|
defaultValue: defaultValue ?? "",
|
|
1116
1140
|
onChange: onValueChange
|
|
1117
1141
|
});
|
|
1142
|
+
const [opened, setOpened] = useState(false);
|
|
1143
|
+
const [active, setActive] = useState();
|
|
1144
|
+
const baseId = useId();
|
|
1145
|
+
const root = useRef(null);
|
|
1146
|
+
const list = useRef(null);
|
|
1147
|
+
const search = useRef(NO_SEARCH);
|
|
1148
|
+
const pointer = useRef(void 0);
|
|
1149
|
+
if (opened && control.disabled) setOpened(false);
|
|
1150
|
+
const open = opened && !control.disabled;
|
|
1151
|
+
const selected = options.find((option) => option.value === current);
|
|
1152
|
+
const activeIndex = open ? options.findIndex((option) => option.value === active?.value) : -1;
|
|
1153
|
+
const listId = `${baseId}-list`;
|
|
1154
|
+
const activeId = activeIndex === -1 ? void 0 : `${baseId}-option-${activeIndex}`;
|
|
1155
|
+
/** Abre la lista con una opción resaltada: la indicada o, si no, la elegida. */
|
|
1156
|
+
function show(keyboard, highlighted = selected?.disabled === true ? void 0 : selected) {
|
|
1157
|
+
setActive(highlighted === void 0 ? void 0 : {
|
|
1158
|
+
value: highlighted.value,
|
|
1159
|
+
keyboard
|
|
1160
|
+
});
|
|
1161
|
+
setOpened(true);
|
|
1162
|
+
if (keyboard) pointer.current = void 0;
|
|
1163
|
+
}
|
|
1164
|
+
function choose(next) {
|
|
1165
|
+
setCurrent(next);
|
|
1166
|
+
setOpened(false);
|
|
1167
|
+
}
|
|
1168
|
+
useLayoutEffect(() => {
|
|
1169
|
+
const anchor = root.current;
|
|
1170
|
+
const popup = list.current;
|
|
1171
|
+
if (!open || anchor === null || popup === null) return;
|
|
1172
|
+
let above = false;
|
|
1173
|
+
const place = () => {
|
|
1174
|
+
const { top, bottom, left, width } = anchor.getBoundingClientRect();
|
|
1175
|
+
const viewport = document.documentElement.clientHeight;
|
|
1176
|
+
popup.dataset.side = above ? "top" : "bottom";
|
|
1177
|
+
popup.style.setProperty("--select-list-left", `${left}px`);
|
|
1178
|
+
popup.style.setProperty("--select-list-width", `${width}px`);
|
|
1179
|
+
popup.style.setProperty("--select-list-offset", `${above ? viewport - top : bottom}px`);
|
|
1180
|
+
popup.style.setProperty("--select-list-space", `${above ? top : viewport - bottom}px`);
|
|
1181
|
+
};
|
|
1182
|
+
const { top, bottom, width } = anchor.getBoundingClientRect();
|
|
1183
|
+
popup.style.setProperty("--select-list-width", `${width}px`);
|
|
1184
|
+
if (typeof popup.showPopover === "function" && !popup.matches(":popover-open")) popup.showPopover();
|
|
1185
|
+
const wanted = popup.offsetHeight + parseFloat(getComputedStyle(popup).marginTop) * 2;
|
|
1186
|
+
const below = document.documentElement.clientHeight - bottom;
|
|
1187
|
+
above = below < wanted && top > below;
|
|
1188
|
+
place();
|
|
1189
|
+
const chosen = popup.querySelector("[aria-selected=\"true\"]");
|
|
1190
|
+
if (chosen !== null) popup.scrollTop = chosen.offsetTop - (popup.clientHeight - chosen.offsetHeight) / 2;
|
|
1191
|
+
const handlePointerDown = (event) => {
|
|
1192
|
+
if (event.target instanceof Node && !anchor.contains(event.target)) setOpened(false);
|
|
1193
|
+
};
|
|
1194
|
+
const handleScroll = (event) => {
|
|
1195
|
+
if (event.target instanceof Node && popup.contains(event.target)) return;
|
|
1196
|
+
place();
|
|
1197
|
+
};
|
|
1198
|
+
document.addEventListener("pointerdown", handlePointerDown, true);
|
|
1199
|
+
window.addEventListener("scroll", handleScroll, true);
|
|
1200
|
+
window.addEventListener("resize", place);
|
|
1201
|
+
return () => {
|
|
1202
|
+
document.removeEventListener("pointerdown", handlePointerDown, true);
|
|
1203
|
+
window.removeEventListener("scroll", handleScroll, true);
|
|
1204
|
+
window.removeEventListener("resize", place);
|
|
1205
|
+
};
|
|
1206
|
+
}, [open]);
|
|
1207
|
+
useLayoutEffect(() => {
|
|
1208
|
+
if (activeId !== void 0) document.getElementById(activeId)?.scrollIntoView({ block: "nearest" });
|
|
1209
|
+
}, [activeId]);
|
|
1210
|
+
function handleClick(event) {
|
|
1211
|
+
event.currentTarget.focus();
|
|
1212
|
+
pointer.current = {
|
|
1213
|
+
x: event.clientX,
|
|
1214
|
+
y: event.clientY
|
|
1215
|
+
};
|
|
1216
|
+
if (open) setOpened(false);
|
|
1217
|
+
else show(false);
|
|
1218
|
+
}
|
|
1219
|
+
function handlePointerMove(event, option) {
|
|
1220
|
+
if (event.pointerType === "touch") return;
|
|
1221
|
+
const last = pointer.current;
|
|
1222
|
+
pointer.current = {
|
|
1223
|
+
x: event.clientX,
|
|
1224
|
+
y: event.clientY
|
|
1225
|
+
};
|
|
1226
|
+
if (last === void 0 || last.x === event.clientX && last.y === event.clientY) return;
|
|
1227
|
+
if (option.disabled === true) return;
|
|
1228
|
+
if (active?.value !== option.value || active.keyboard) setActive({
|
|
1229
|
+
value: option.value,
|
|
1230
|
+
keyboard: false
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
function handleKeyDown(event) {
|
|
1234
|
+
const { key } = event;
|
|
1235
|
+
if (event.ctrlKey || event.metaKey) return;
|
|
1236
|
+
const searching = event.timeStamp - search.current.at < SEARCH_TIMEOUT_MS;
|
|
1237
|
+
if (key.length === 1 && !event.altKey && (key !== " " || searching)) {
|
|
1238
|
+
event.preventDefault();
|
|
1239
|
+
const text = searching ? search.current.text + key : key;
|
|
1240
|
+
search.current = {
|
|
1241
|
+
text,
|
|
1242
|
+
at: event.timeStamp
|
|
1243
|
+
};
|
|
1244
|
+
const match = findOptionByText(options, text, open ? active?.value : selected?.value);
|
|
1245
|
+
const option = options.find((candidate) => candidate.value === match);
|
|
1246
|
+
if (!open) show(true, option);
|
|
1247
|
+
else if (option !== void 0) setActive({
|
|
1248
|
+
value: option.value,
|
|
1249
|
+
keyboard: true
|
|
1250
|
+
});
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
const direction = keyDirection$1[key];
|
|
1254
|
+
const confirms = key === "Enter" || key === " ";
|
|
1255
|
+
if (direction === void 0 && !confirms && key !== "Escape" && key !== "Tab") return;
|
|
1256
|
+
search.current = NO_SEARCH;
|
|
1257
|
+
if (key === "Escape") {
|
|
1258
|
+
if (!open) return;
|
|
1259
|
+
event.preventDefault();
|
|
1260
|
+
event.stopPropagation();
|
|
1261
|
+
setOpened(false);
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
if (key === "Tab") {
|
|
1265
|
+
if (open && active !== void 0) choose(active.value);
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
event.preventDefault();
|
|
1269
|
+
if (!open) {
|
|
1270
|
+
const value = direction === "first" || direction === "last" ? getOptionInDirection(options, void 0, direction) : void 0;
|
|
1271
|
+
show(true, options.find((option) => option.value === value));
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
if (confirms || event.altKey && key === "ArrowUp") {
|
|
1275
|
+
if (active === void 0) setOpened(false);
|
|
1276
|
+
else choose(active.value);
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
if (direction === void 0 || event.altKey) return;
|
|
1280
|
+
const next = getOptionInDirection(options, active?.value, direction);
|
|
1281
|
+
setActive(next === void 0 ? void 0 : {
|
|
1282
|
+
value: next,
|
|
1283
|
+
keyboard: true
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1118
1286
|
return /* @__PURE__ */ jsxs("div", {
|
|
1287
|
+
ref: root,
|
|
1119
1288
|
className: cx(field_module_default.field, Select_module_default.root, sizeClass[size], control.invalid && field_module_default.invalid, control.disabled && field_module_default.disabled, className),
|
|
1120
1289
|
style,
|
|
1121
|
-
children: [
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1290
|
+
children: [
|
|
1291
|
+
/* @__PURE__ */ jsx("button", {
|
|
1292
|
+
ref,
|
|
1293
|
+
type: "button",
|
|
1294
|
+
role: "combobox",
|
|
1295
|
+
id: control.id,
|
|
1296
|
+
className: cx(field_module_default.control, Select_module_default.trigger, selected === void 0 && Select_module_default.placeholder),
|
|
1297
|
+
disabled: control.disabled,
|
|
1298
|
+
"aria-haspopup": "listbox",
|
|
1299
|
+
"aria-expanded": open,
|
|
1300
|
+
"aria-controls": open ? listId : void 0,
|
|
1301
|
+
"aria-activedescendant": activeId,
|
|
1302
|
+
"aria-label": accessibilityLabel,
|
|
1303
|
+
"aria-describedby": control.describedBy,
|
|
1304
|
+
"aria-invalid": control.invalid ? true : void 0,
|
|
1305
|
+
"aria-required": control.required ? true : void 0,
|
|
1306
|
+
"data-testid": testID,
|
|
1307
|
+
onClick: handleClick,
|
|
1308
|
+
onKeyDown: handleKeyDown,
|
|
1309
|
+
onKeyUp: (event) => {
|
|
1310
|
+
if (event.key === " ") event.preventDefault();
|
|
1311
|
+
},
|
|
1312
|
+
onBlur: () => setOpened(false),
|
|
1313
|
+
children: selected?.label ?? placeholder ?? ""
|
|
1314
|
+
}),
|
|
1315
|
+
/* @__PURE__ */ jsx("span", {
|
|
1316
|
+
className: Select_module_default.chevron,
|
|
1317
|
+
"aria-hidden": "true",
|
|
1318
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
1319
|
+
name: "chevron-down",
|
|
1320
|
+
size: inputIconSize[size],
|
|
1321
|
+
color: control.disabled ? "disabled" : "muted"
|
|
1322
|
+
})
|
|
1323
|
+
}),
|
|
1324
|
+
open ? /* @__PURE__ */ jsx("div", {
|
|
1325
|
+
ref: list,
|
|
1326
|
+
popover: "manual",
|
|
1327
|
+
role: "listbox",
|
|
1328
|
+
id: listId,
|
|
1329
|
+
tabIndex: -1,
|
|
1330
|
+
"aria-label": control.accessibilityLabel,
|
|
1331
|
+
className: Select_module_default.list,
|
|
1332
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
1333
|
+
children: options.map((option, index) => {
|
|
1334
|
+
const isSelected = option.value === current;
|
|
1335
|
+
const isDisabled = option.disabled === true;
|
|
1336
|
+
const isActive = index === activeIndex;
|
|
1337
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1338
|
+
id: `${baseId}-option-${index}`,
|
|
1339
|
+
role: "option",
|
|
1340
|
+
"aria-selected": isSelected,
|
|
1341
|
+
"aria-disabled": isDisabled ? true : void 0,
|
|
1342
|
+
className: cx(Select_module_default.option, isActive && (active?.keyboard === true ? Select_module_default.focused : Select_module_default.active), isDisabled && Select_module_default.disabled),
|
|
1343
|
+
onClick: isDisabled ? void 0 : () => choose(option.value),
|
|
1344
|
+
onPointerMove: (event) => handlePointerMove(event, option),
|
|
1345
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1346
|
+
className: Select_module_default.label,
|
|
1347
|
+
children: option.label
|
|
1348
|
+
}), isSelected ? /* @__PURE__ */ jsx(Icon, {
|
|
1349
|
+
name: "check",
|
|
1350
|
+
size: inputIconSize[size],
|
|
1351
|
+
color: "link"
|
|
1352
|
+
}) : null]
|
|
1353
|
+
}, option.value);
|
|
1354
|
+
})
|
|
1355
|
+
}) : null,
|
|
1356
|
+
name === void 0 ? null : /* @__PURE__ */ jsx("input", {
|
|
1357
|
+
type: "hidden",
|
|
1358
|
+
name,
|
|
1359
|
+
value: current,
|
|
1360
|
+
disabled: control.disabled
|
|
1151
1361
|
})
|
|
1152
|
-
|
|
1362
|
+
]
|
|
1153
1363
|
});
|
|
1154
1364
|
}
|
|
1155
1365
|
//#endregion
|
package/dist/web/styles.css
CHANGED
|
@@ -784,27 +784,26 @@
|
|
|
784
784
|
--select-icon: var(--space-5);
|
|
785
785
|
}
|
|
786
786
|
|
|
787
|
-
.sui-
|
|
787
|
+
.sui-trigger-Rxx4wG {
|
|
788
788
|
min-height: calc(var(--select-height) - var(--border-width-thin) * 2);
|
|
789
789
|
padding: var(--space-0) calc(var(--select-padding-x) + var(--select-icon) + var(--space-2))
|
|
790
790
|
var(--space-0) var(--select-padding-x);
|
|
791
791
|
border-radius: inherit;
|
|
792
|
+
text-align: start;
|
|
792
793
|
text-overflow: ellipsis;
|
|
794
|
+
white-space: nowrap;
|
|
793
795
|
cursor: inherit;
|
|
796
|
+
-webkit-tap-highlight-color: transparent;
|
|
794
797
|
align-self: stretch;
|
|
798
|
+
overflow: hidden;
|
|
795
799
|
}
|
|
796
800
|
|
|
797
801
|
.sui-placeholder-Rxx4wG {
|
|
798
802
|
color: var(--color-text-muted);
|
|
799
803
|
}
|
|
800
804
|
|
|
801
|
-
.sui-
|
|
802
|
-
|
|
803
|
-
color: var(--color-text-primary);
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
.sui-select-Rxx4wG option:disabled {
|
|
807
|
-
color: var(--color-text-disabled);
|
|
805
|
+
.sui-placeholder-Rxx4wG:disabled {
|
|
806
|
+
color: inherit;
|
|
808
807
|
}
|
|
809
808
|
|
|
810
809
|
.sui-chevron-Rxx4wG {
|
|
@@ -812,10 +811,85 @@
|
|
|
812
811
|
right: var(--select-padding-x);
|
|
813
812
|
bottom: var(--space-0);
|
|
814
813
|
pointer-events: none;
|
|
814
|
+
transition: transform var(--duration-fast);
|
|
815
815
|
align-items: center;
|
|
816
816
|
display: flex;
|
|
817
817
|
position: absolute;
|
|
818
818
|
}
|
|
819
|
+
|
|
820
|
+
.sui-trigger-Rxx4wG[aria-expanded="true"] + .sui-chevron-Rxx4wG {
|
|
821
|
+
transform: rotate(180deg);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.sui-list-Rxx4wG {
|
|
825
|
+
inset: auto;
|
|
826
|
+
top: var(--select-list-offset);
|
|
827
|
+
left: var(--select-list-left);
|
|
828
|
+
z-index: var(--z-index-dropdown);
|
|
829
|
+
box-sizing: border-box;
|
|
830
|
+
width: max-content;
|
|
831
|
+
min-width: var(--select-list-width);
|
|
832
|
+
max-width: calc(100vw - var(--select-list-left, 0px) - var(--space-2));
|
|
833
|
+
max-height: min(calc(var(--size-control-md) * 7),
|
|
834
|
+
calc(var(--select-list-space, 100vh) - var(--space-1) * 2));
|
|
835
|
+
margin: var(--space-1) var(--space-0);
|
|
836
|
+
padding: var(--space-1);
|
|
837
|
+
overscroll-behavior: contain;
|
|
838
|
+
scroll-padding-block: var(--space-1);
|
|
839
|
+
scrollbar-color: var(--color-border-strong) transparent;
|
|
840
|
+
scrollbar-width: thin;
|
|
841
|
+
border: var(--border-width-thin) solid var(--color-border-default);
|
|
842
|
+
border-radius: var(--radius-md);
|
|
843
|
+
background-color: var(--color-bg-elevated);
|
|
844
|
+
box-shadow: var(--shadow-md);
|
|
845
|
+
color: var(--color-text-primary);
|
|
846
|
+
cursor: default;
|
|
847
|
+
position: fixed;
|
|
848
|
+
overflow-y: auto;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.sui-list-Rxx4wG[data-side="top"] {
|
|
852
|
+
top: auto;
|
|
853
|
+
bottom: var(--select-list-offset);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.sui-option-Rxx4wG {
|
|
857
|
+
align-items: center;
|
|
858
|
+
gap: var(--space-2);
|
|
859
|
+
box-sizing: border-box;
|
|
860
|
+
min-height: var(--select-height);
|
|
861
|
+
padding: var(--space-2) calc(var(--select-padding-x) - var(--space-1));
|
|
862
|
+
border-radius: var(--radius-sm);
|
|
863
|
+
cursor: pointer;
|
|
864
|
+
-webkit-tap-highlight-color: transparent;
|
|
865
|
+
display: flex;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
.sui-label-Rxx4wG {
|
|
869
|
+
overflow-wrap: anywhere;
|
|
870
|
+
flex: auto;
|
|
871
|
+
min-width: 0;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
.sui-active-Rxx4wG, .sui-option-Rxx4wG:active:not(.sui-disabled-Rxx4wG) {
|
|
875
|
+
background-color: var(--color-bg-muted);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
.sui-focused-Rxx4wG {
|
|
879
|
+
outline: var(--border-width-thick) solid var(--color-border-focus);
|
|
880
|
+
outline-offset: calc(var(--border-width-thick) * -1);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.sui-disabled-Rxx4wG {
|
|
884
|
+
color: var(--color-text-disabled);
|
|
885
|
+
cursor: not-allowed;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
@media (prefers-reduced-motion: reduce) {
|
|
889
|
+
.sui-chevron-Rxx4wG {
|
|
890
|
+
transition: none;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
819
893
|
.sui-root-KsqoQq {
|
|
820
894
|
--skeleton-width: initial;
|
|
821
895
|
--skeleton-height: initial;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@satellatickets/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Componentes de satella-ui con una sola API para React (web) y React Native",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@satellatickets/core": "0.
|
|
57
|
+
"@satellatickets/core": "0.3.0",
|
|
58
58
|
"@satellatickets/tokens": "0.1.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"tsdown": "^0.23.0",
|
|
81
81
|
"typescript": "^5.9.3",
|
|
82
82
|
"@satellatickets/eslint-config": "0.0.0",
|
|
83
|
-
"@satellatickets/
|
|
84
|
-
"@satellatickets/
|
|
83
|
+
"@satellatickets/tsconfig": "0.0.0",
|
|
84
|
+
"@satellatickets/icons": "0.0.0"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "tsdown",
|