@reopt-ai/opt-ui 1.8.0 → 1.10.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/COMPONENT_CATALOG.md +222 -34
- package/README.md +70 -6
- package/dist/core/index.cjs +170 -155
- package/dist/core/index.d.cts +3 -2
- package/dist/core/index.d.ts +3 -2
- package/dist/core/index.js +3 -3
- package/dist/docs/02-components/01-core.md +223 -18
- package/dist/docs/02-components/02-visuals.md +1 -1
- package/dist/docs/02-components/03-shells.md +17 -16
- package/dist/docs/02-components/04-surfaces.md +1 -1
- package/dist/docs/02-components/index.md +4 -4
- package/dist/{field-sidebar-Bqfp6dgg.cjs → field-sidebar-B6Ndr8HE.cjs} +304 -289
- package/dist/{field-sidebar-BYD_UIjG.js → field-sidebar-BXjvV7Cz.js} +25 -10
- package/dist/{field-sidebar-BYD_UIjG.js.map → field-sidebar-BXjvV7Cz.js.map} +1 -1
- package/dist/{field-sidebar-5KYVlpSs.d.ts → field-sidebar-DWfJAJlx.d.ts} +32 -3
- package/dist/{field-sidebar-5KYVlpSs.d.ts.map → field-sidebar-DWfJAJlx.d.ts.map} +1 -1
- package/dist/{field-sidebar-BP0iWkoV.d.cts → field-sidebar-nwcE9LC4.d.cts} +32 -3
- package/dist/{field-sidebar-BP0iWkoV.d.cts.map → field-sidebar-nwcE9LC4.d.cts.map} +1 -1
- package/dist/id-registry.cjs +98 -2
- package/dist/id-registry.d.cts.map +1 -1
- package/dist/id-registry.d.ts.map +1 -1
- package/dist/id-registry.js +98 -2
- package/dist/id-registry.js.map +1 -1
- package/dist/id-registry.json +202 -4
- package/dist/index.cjs +664 -643
- package/dist/index.d.cts +5 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/{shader-surface-BUPZ0P-n.js → key-pad-menu-BQunU20e.js} +727 -19
- package/dist/key-pad-menu-BQunU20e.js.map +1 -0
- package/dist/{shader-surface-BfTP9c1Q.d.ts → key-pad-menu-BsgJMjD4.d.ts} +415 -3
- package/dist/key-pad-menu-BsgJMjD4.d.ts.map +1 -0
- package/dist/{shader-surface-Fav5K9UC.cjs → key-pad-menu-D5mQcS5v.cjs} +969 -201
- package/dist/{shader-surface-DRrcLrWf.d.cts → key-pad-menu-DfZbeXhG.d.cts} +415 -3
- package/dist/key-pad-menu-DfZbeXhG.d.cts.map +1 -0
- package/dist/meta.cjs +641 -0
- package/dist/meta.d.cts.map +1 -1
- package/dist/meta.d.ts.map +1 -1
- package/dist/meta.js +641 -0
- package/dist/meta.js.map +1 -1
- package/dist/shells/index.cjs +1 -1
- package/dist/shells/index.d.cts +1 -1
- package/dist/shells/index.d.ts +1 -1
- package/dist/shells/index.js +1 -1
- package/dist/{types-D0FlcYnM.d.ts → text-truncate-BGr7bB_8.d.cts} +110 -2
- package/dist/text-truncate-BGr7bB_8.d.cts.map +1 -0
- package/dist/{types-D0FlcYnM.d.cts → text-truncate-BGr7bB_8.d.ts} +110 -2
- package/dist/text-truncate-BGr7bB_8.d.ts.map +1 -0
- package/dist/{pagination-DjfxBcjX.cjs → text-truncate-CxdzAnhS.cjs} +418 -8
- package/dist/{pagination-DWbvACuN.js → text-truncate-j6X3z7Pv.js} +392 -12
- package/dist/text-truncate-j6X3z7Pv.js.map +1 -0
- package/package.json +3 -3
- package/dist/pagination-DWbvACuN.js.map +0 -1
- package/dist/shader-surface-BUPZ0P-n.js.map +0 -1
- package/dist/shader-surface-BfTP9c1Q.d.ts.map +0 -1
- package/dist/shader-surface-DRrcLrWf.d.cts.map +0 -1
- package/dist/types-D0FlcYnM.d.cts.map +0 -1
- package/dist/types-D0FlcYnM.d.ts.map +0 -1
|
@@ -346,7 +346,7 @@ const variantStyles$2 = {
|
|
|
346
346
|
ghost: "text-text-secondary hover:bg-bg-subtle active:bg-bg-muted focus-visible:ring-offset-1",
|
|
347
347
|
danger: "bg-danger text-danger-fg hover:bg-danger active:bg-danger focus-visible:ring-offset-2"
|
|
348
348
|
};
|
|
349
|
-
const sizeStyles$
|
|
349
|
+
const sizeStyles$4 = {
|
|
350
350
|
sm: "h-[var(--opt-control-sm)] px-[var(--opt-control-padding-sm)] text-xs gap-[var(--opt-space-1-5)]",
|
|
351
351
|
md: "h-[var(--opt-control-md)] px-[var(--opt-control-padding-md)] text-sm gap-[var(--opt-space-2)]",
|
|
352
352
|
lg: "h-[var(--opt-control-lg)] px-[var(--opt-control-padding-lg)] text-base gap-[var(--opt-space-2)]"
|
|
@@ -357,7 +357,7 @@ function Button(_ref) {
|
|
|
357
357
|
const isDisabled = disabled || loading;
|
|
358
358
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", _objectSpread2(_objectSpread2({
|
|
359
359
|
type: "button",
|
|
360
|
-
className: cn("inline-flex cursor-pointer items-center justify-center rounded-lg font-medium transition-colors", OPT_FOCUS_VISIBLE, variantStyles$2[variant], sizeStyles$
|
|
360
|
+
className: cn("inline-flex cursor-pointer items-center justify-center rounded-lg font-medium transition-colors", OPT_FOCUS_VISIBLE, variantStyles$2[variant], sizeStyles$4[size], isDisabled && "pointer-events-none cursor-not-allowed opacity-50", className),
|
|
361
361
|
disabled: isDisabled
|
|
362
362
|
}, props), {}, {
|
|
363
363
|
"aria-busy": loading ? true : ariaBusy,
|
|
@@ -466,7 +466,7 @@ const progressStroke = {
|
|
|
466
466
|
error: "stroke-danger",
|
|
467
467
|
info: "stroke-info"
|
|
468
468
|
};
|
|
469
|
-
const sizeStyles$
|
|
469
|
+
const sizeStyles$3 = {
|
|
470
470
|
sm: "px-1.5 py-0.5 text-[10px]",
|
|
471
471
|
md: "px-2 py-0.5 text-[11px]"
|
|
472
472
|
};
|
|
@@ -478,7 +478,7 @@ function Badge(_ref) {
|
|
|
478
478
|
const radius = (progressSize - 3) / 2;
|
|
479
479
|
const circumference = 2 * Math.PI * radius;
|
|
480
480
|
const offset = circumference - clampedProgress / 100 * circumference;
|
|
481
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", _objectSpread2(_objectSpread2({ className: cn(OPT_BADGE, variantStyles$1[variant], sizeStyles$
|
|
481
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", _objectSpread2(_objectSpread2({ className: cn(OPT_BADGE, variantStyles$1[variant], sizeStyles$3[size], className) }, props), {}, {
|
|
482
482
|
"data-opt-id": "9GBGZ",
|
|
483
483
|
"data-opt-slug": "badge.Badge",
|
|
484
484
|
children: [
|
|
@@ -525,7 +525,7 @@ const _excluded$13 = [
|
|
|
525
525
|
"aria-hidden",
|
|
526
526
|
"aria-label"
|
|
527
527
|
];
|
|
528
|
-
const sizeStyles$
|
|
528
|
+
const sizeStyles$2 = {
|
|
529
529
|
sm: "h-4 w-4",
|
|
530
530
|
md: "h-6 w-6",
|
|
531
531
|
lg: "h-8 w-8"
|
|
@@ -535,7 +535,7 @@ function Spinner(_ref) {
|
|
|
535
535
|
let { size = "md", className, role, "aria-hidden": ariaHidden, "aria-label": ariaLabel } = _ref, props = _objectWithoutProperties(_ref, _excluded$13);
|
|
536
536
|
const isDecorative = ariaHidden === true || ariaHidden === "true";
|
|
537
537
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", _objectSpread2(_objectSpread2({
|
|
538
|
-
className: cn("animate-spin text-current", sizeStyles$
|
|
538
|
+
className: cn("animate-spin text-current", sizeStyles$2[size], className),
|
|
539
539
|
viewBox: "0 0 24 24",
|
|
540
540
|
fill: "none",
|
|
541
541
|
role: isDecorative ? void 0 : role !== null && role !== void 0 ? role : "status",
|
|
@@ -3554,7 +3554,7 @@ function setForwardedRef(ref, value) {
|
|
|
3554
3554
|
if (typeof ref === "function") ref(value);
|
|
3555
3555
|
else if (ref) ref.current = value;
|
|
3556
3556
|
}
|
|
3557
|
-
const sizeStyles = {
|
|
3557
|
+
const sizeStyles$1 = {
|
|
3558
3558
|
sm: {
|
|
3559
3559
|
box: "h-4 w-4",
|
|
3560
3560
|
icon: "h-3 w-3",
|
|
@@ -3620,7 +3620,7 @@ const Checkbox = (0, react.forwardRef)((_ref, ref) => {
|
|
|
3620
3620
|
const checkboxId = (_useInputId = useInputId(id, label, "checkbox")) !== null && _useInputId !== void 0 ? _useInputId : `checkbox-${fallbackId}`;
|
|
3621
3621
|
const hintText = hint !== null && hint !== void 0 ? hint : description;
|
|
3622
3622
|
const hasError = Boolean(error);
|
|
3623
|
-
const styles = sizeStyles[size];
|
|
3623
|
+
const styles = sizeStyles$1[size];
|
|
3624
3624
|
const isIndeterminate = Boolean(indeterminate);
|
|
3625
3625
|
const inputRef = (0, react.useCallback)((node) => {
|
|
3626
3626
|
if (node) node.indeterminate = isIndeterminate;
|
|
@@ -3867,6 +3867,386 @@ function Pagination(_ref) {
|
|
|
3867
3867
|
}));
|
|
3868
3868
|
}
|
|
3869
3869
|
//#endregion
|
|
3870
|
+
//#region src/core/field-token.tsx
|
|
3871
|
+
/**
|
|
3872
|
+
* The glyph and palette slot each field type reads as. Exported so a product
|
|
3873
|
+
* can render the same legend the tokens imply.
|
|
3874
|
+
*/
|
|
3875
|
+
const FIELD_TYPE_TOKENS = {
|
|
3876
|
+
string: {
|
|
3877
|
+
icon: lucide_react.Type,
|
|
3878
|
+
tone: 1,
|
|
3879
|
+
name: "String"
|
|
3880
|
+
},
|
|
3881
|
+
number: {
|
|
3882
|
+
icon: lucide_react.Hash,
|
|
3883
|
+
tone: 2,
|
|
3884
|
+
name: "Number"
|
|
3885
|
+
},
|
|
3886
|
+
boolean: {
|
|
3887
|
+
icon: lucide_react.ToggleLeft,
|
|
3888
|
+
tone: 3,
|
|
3889
|
+
name: "Boolean"
|
|
3890
|
+
},
|
|
3891
|
+
date: {
|
|
3892
|
+
icon: lucide_react.Calendar,
|
|
3893
|
+
tone: 4,
|
|
3894
|
+
name: "Date"
|
|
3895
|
+
},
|
|
3896
|
+
datetime: {
|
|
3897
|
+
icon: lucide_react.CalendarClock,
|
|
3898
|
+
tone: 4,
|
|
3899
|
+
name: "Date and time"
|
|
3900
|
+
},
|
|
3901
|
+
duration: {
|
|
3902
|
+
icon: lucide_react.Timer,
|
|
3903
|
+
tone: 5,
|
|
3904
|
+
name: "Duration"
|
|
3905
|
+
},
|
|
3906
|
+
percent: {
|
|
3907
|
+
icon: lucide_react.Percent,
|
|
3908
|
+
tone: 6,
|
|
3909
|
+
name: "Percent"
|
|
3910
|
+
},
|
|
3911
|
+
currency: {
|
|
3912
|
+
icon: lucide_react.CircleDollarSign,
|
|
3913
|
+
tone: 7,
|
|
3914
|
+
name: "Currency"
|
|
3915
|
+
},
|
|
3916
|
+
enum: {
|
|
3917
|
+
icon: lucide_react.List,
|
|
3918
|
+
tone: 8,
|
|
3919
|
+
name: "Enum"
|
|
3920
|
+
},
|
|
3921
|
+
array: {
|
|
3922
|
+
icon: lucide_react.Brackets,
|
|
3923
|
+
tone: 9,
|
|
3924
|
+
name: "Array"
|
|
3925
|
+
},
|
|
3926
|
+
object: {
|
|
3927
|
+
icon: lucide_react.Braces,
|
|
3928
|
+
tone: 10,
|
|
3929
|
+
name: "Object"
|
|
3930
|
+
},
|
|
3931
|
+
json: {
|
|
3932
|
+
icon: lucide_react.Braces,
|
|
3933
|
+
tone: 10,
|
|
3934
|
+
name: "JSON"
|
|
3935
|
+
},
|
|
3936
|
+
ip: {
|
|
3937
|
+
icon: lucide_react.Network,
|
|
3938
|
+
tone: 11,
|
|
3939
|
+
name: "IP address"
|
|
3940
|
+
},
|
|
3941
|
+
geo: {
|
|
3942
|
+
icon: lucide_react.MapPin,
|
|
3943
|
+
tone: 12,
|
|
3944
|
+
name: "Geo point"
|
|
3945
|
+
},
|
|
3946
|
+
url: {
|
|
3947
|
+
icon: lucide_react.Link2,
|
|
3948
|
+
tone: 13,
|
|
3949
|
+
name: "URL"
|
|
3950
|
+
},
|
|
3951
|
+
email: {
|
|
3952
|
+
icon: lucide_react.AtSign,
|
|
3953
|
+
tone: 14,
|
|
3954
|
+
name: "Email"
|
|
3955
|
+
},
|
|
3956
|
+
id: {
|
|
3957
|
+
icon: lucide_react.Fingerprint,
|
|
3958
|
+
tone: 15,
|
|
3959
|
+
name: "Identifier"
|
|
3960
|
+
},
|
|
3961
|
+
binary: {
|
|
3962
|
+
icon: lucide_react.Binary,
|
|
3963
|
+
tone: 16,
|
|
3964
|
+
name: "Binary"
|
|
3965
|
+
},
|
|
3966
|
+
aggregate: {
|
|
3967
|
+
icon: lucide_react.Sigma,
|
|
3968
|
+
tone: 2,
|
|
3969
|
+
name: "Aggregate"
|
|
3970
|
+
},
|
|
3971
|
+
nested: {
|
|
3972
|
+
icon: lucide_react.Layers,
|
|
3973
|
+
tone: 9,
|
|
3974
|
+
name: "Nested"
|
|
3975
|
+
},
|
|
3976
|
+
unknown: {
|
|
3977
|
+
icon: lucide_react.CircleHelp,
|
|
3978
|
+
tone: 0,
|
|
3979
|
+
name: "Unknown"
|
|
3980
|
+
}
|
|
3981
|
+
};
|
|
3982
|
+
/**
|
|
3983
|
+
* Names a backend type as one of ours. Accepts the spellings Postgres,
|
|
3984
|
+
* ClickHouse, DuckDB, and JSON Schema actually emit, so a caller can hand
|
|
3985
|
+
* over a column type verbatim instead of maintaining its own table.
|
|
3986
|
+
*/
|
|
3987
|
+
function resolveFieldType(raw) {
|
|
3988
|
+
if (!raw) return "unknown";
|
|
3989
|
+
const t = raw.trim().toLowerCase();
|
|
3990
|
+
if (t in FIELD_TYPE_TOKENS) return t;
|
|
3991
|
+
if (t.endsWith("[]")) return "array";
|
|
3992
|
+
if (/^(array|list|set|multi)/.test(t)) return "array";
|
|
3993
|
+
if (/^(bytea|blob|binary|fixedstring)/.test(t)) return "binary";
|
|
3994
|
+
if (/^bool/.test(t)) return "boolean";
|
|
3995
|
+
if (/^(timestamp|datetime)/.test(t)) return "datetime";
|
|
3996
|
+
if (/^date/.test(t)) return "date";
|
|
3997
|
+
if (/^interval/.test(t)) return "duration";
|
|
3998
|
+
if (/^(uuid|guid)/.test(t)) return "id";
|
|
3999
|
+
if (/^(inet|cidr|ipv?[46])/.test(t)) return "ip";
|
|
4000
|
+
if (/^(point|geo|geography|geometry|latlon)/.test(t)) return "geo";
|
|
4001
|
+
if (/^(jsonb?|map|struct|record|tuple)/.test(t)) return "json";
|
|
4002
|
+
if (/^(enum|lowcardinality|category|categorical)/.test(t)) return "enum";
|
|
4003
|
+
if (/^(u?int|float|double|decimal|numeric|real|bigint|smallint|tinyint|serial|money)/.test(t)) return "number";
|
|
4004
|
+
if (/^(text|n?varchar|n?char|keyword|str|string)/.test(t)) return "string";
|
|
4005
|
+
return "unknown";
|
|
4006
|
+
}
|
|
4007
|
+
const sizeStyles = {
|
|
4008
|
+
xs: "size-4 rounded-[3px] [&>svg]:size-2.5",
|
|
4009
|
+
sm: "size-5 rounded [&>svg]:size-3",
|
|
4010
|
+
md: "size-6 rounded-md [&>svg]:size-3.5",
|
|
4011
|
+
lg: "size-8 rounded-lg [&>svg]:size-4"
|
|
4012
|
+
};
|
|
4013
|
+
const shapeStyles = {
|
|
4014
|
+
square: "",
|
|
4015
|
+
circle: "rounded-full"
|
|
4016
|
+
};
|
|
4017
|
+
/**
|
|
4018
|
+
* FieldToken — the type of a field, as a glyph.
|
|
4019
|
+
*
|
|
4020
|
+
* A field list, a column header, and a property table all have to answer
|
|
4021
|
+
* "what kind of thing is this?" before anything else, and they have to answer
|
|
4022
|
+
* it in the width of an icon. This is that answer: one glyph per type, one
|
|
4023
|
+
* palette slot per glyph, stable across every surface that shows fields, so a
|
|
4024
|
+
* reader learns the vocabulary once.
|
|
4025
|
+
*
|
|
4026
|
+
* @example
|
|
4027
|
+
* ```tsx
|
|
4028
|
+
* <FieldToken type={resolveFieldType(column.dataType)} title={column.name} />
|
|
4029
|
+
* ```
|
|
4030
|
+
*/
|
|
4031
|
+
function FieldToken({ type, size = "sm", fill = "subtle", shape = "square", title, decorative = false, className }) {
|
|
4032
|
+
var _FIELD_TYPE_TOKENS$ty;
|
|
4033
|
+
const appearance = (_FIELD_TYPE_TOKENS$ty = FIELD_TYPE_TOKENS[type]) !== null && _FIELD_TYPE_TOKENS$ty !== void 0 ? _FIELD_TYPE_TOKENS$ty : FIELD_TYPE_TOKENS.unknown;
|
|
4034
|
+
const Icon = appearance.icon;
|
|
4035
|
+
const label = title !== null && title !== void 0 ? title : appearance.name;
|
|
4036
|
+
const hue = appearance.tone === 0 ? "var(--color-text-tertiary)" : `var(--opt-chart-${appearance.tone})`;
|
|
4037
|
+
const style = fill === "solid" ? {
|
|
4038
|
+
backgroundColor: hue,
|
|
4039
|
+
color: "var(--color-surface)"
|
|
4040
|
+
} : fill === "subtle" ? {
|
|
4041
|
+
backgroundColor: `color-mix(in oklab, ${hue} 14%, transparent)`,
|
|
4042
|
+
color: hue
|
|
4043
|
+
} : { color: hue };
|
|
4044
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4045
|
+
className: cn("inline-flex shrink-0 items-center justify-center", sizeStyles[size], shapeStyles[shape], className),
|
|
4046
|
+
style,
|
|
4047
|
+
role: decorative ? void 0 : "img",
|
|
4048
|
+
"aria-label": decorative ? void 0 : label,
|
|
4049
|
+
"aria-hidden": decorative ? true : void 0,
|
|
4050
|
+
"data-opt-id": "V3AJ4",
|
|
4051
|
+
"data-opt-slug": "field-token.FieldToken",
|
|
4052
|
+
"data-field-type": type,
|
|
4053
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { "aria-hidden": "true" })
|
|
4054
|
+
});
|
|
4055
|
+
}
|
|
4056
|
+
//#endregion
|
|
4057
|
+
//#region src/core/highlight.tsx
|
|
4058
|
+
function escapeForRegExp(value) {
|
|
4059
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4060
|
+
}
|
|
4061
|
+
/**
|
|
4062
|
+
* Splits `text` on every occurrence of every term. Terms are matched longest
|
|
4063
|
+
* first so a search for both "check" and "checkout" marks "checkout" whole
|
|
4064
|
+
* rather than leaving a stray "out".
|
|
4065
|
+
*/
|
|
4066
|
+
function segment(text, terms, caseSensitive, firstOnly) {
|
|
4067
|
+
const usable = terms.filter((term) => term.length > 0).sort((a, b) => b.length - a.length);
|
|
4068
|
+
if (usable.length === 0) return [{
|
|
4069
|
+
text,
|
|
4070
|
+
hit: false
|
|
4071
|
+
}];
|
|
4072
|
+
const pattern = new RegExp(`(${usable.map(escapeForRegExp).join("|")})`, caseSensitive ? "g" : "gi");
|
|
4073
|
+
const out = [];
|
|
4074
|
+
let cursor = 0;
|
|
4075
|
+
let matched = false;
|
|
4076
|
+
for (const match of text.matchAll(pattern)) {
|
|
4077
|
+
var _match$index;
|
|
4078
|
+
if (firstOnly && matched) break;
|
|
4079
|
+
const at = (_match$index = match.index) !== null && _match$index !== void 0 ? _match$index : 0;
|
|
4080
|
+
if (at > cursor) out.push({
|
|
4081
|
+
text: text.slice(cursor, at),
|
|
4082
|
+
hit: false
|
|
4083
|
+
});
|
|
4084
|
+
out.push({
|
|
4085
|
+
text: match[0],
|
|
4086
|
+
hit: true
|
|
4087
|
+
});
|
|
4088
|
+
cursor = at + match[0].length;
|
|
4089
|
+
matched = true;
|
|
4090
|
+
}
|
|
4091
|
+
if (cursor < text.length) out.push({
|
|
4092
|
+
text: text.slice(cursor),
|
|
4093
|
+
hit: false
|
|
4094
|
+
});
|
|
4095
|
+
return out;
|
|
4096
|
+
}
|
|
4097
|
+
/**
|
|
4098
|
+
* Highlight — marks the part of a string the reader searched for.
|
|
4099
|
+
*
|
|
4100
|
+
* Uses a real `<mark>`, so the match is carried by semantics rather than by
|
|
4101
|
+
* colour alone and survives a high-contrast theme. Terms are matched longest
|
|
4102
|
+
* first, so overlapping terms produce whole marks instead of fragments.
|
|
4103
|
+
*
|
|
4104
|
+
* @example
|
|
4105
|
+
* ```tsx
|
|
4106
|
+
* <Highlight text={row.message} search={query} />
|
|
4107
|
+
* ```
|
|
4108
|
+
*/
|
|
4109
|
+
function Highlight({ text, search, caseSensitive = false, firstOnly = false, className, markClassName }) {
|
|
4110
|
+
const segments = segment(text, Array.isArray(search) ? search : [search], caseSensitive, firstOnly);
|
|
4111
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4112
|
+
className,
|
|
4113
|
+
"data-opt-id": "448TR",
|
|
4114
|
+
"data-opt-slug": "highlight.Highlight",
|
|
4115
|
+
children: segments.map((part, index) => part.hit ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("mark", {
|
|
4116
|
+
className: cn("bg-warning-subtle text-text-primary rounded-[2px] px-0.5 font-medium", markClassName),
|
|
4117
|
+
children: part.text
|
|
4118
|
+
}, index) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: part.text }, index))
|
|
4119
|
+
});
|
|
4120
|
+
}
|
|
4121
|
+
//#endregion
|
|
4122
|
+
//#region src/core/text-truncate.tsx
|
|
4123
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? react.useEffect : react.useLayoutEffect;
|
|
4124
|
+
/** Measures text in the element's own resolved font, not an assumed one. */
|
|
4125
|
+
function createMeasurer(element) {
|
|
4126
|
+
const context = document.createElement("canvas").getContext("2d");
|
|
4127
|
+
if (!context) return null;
|
|
4128
|
+
const computed = window.getComputedStyle(element);
|
|
4129
|
+
context.font = [
|
|
4130
|
+
computed.fontStyle,
|
|
4131
|
+
computed.fontVariant,
|
|
4132
|
+
computed.fontWeight,
|
|
4133
|
+
`${computed.fontSize}/${computed.lineHeight}`,
|
|
4134
|
+
computed.fontFamily
|
|
4135
|
+
].join(" ");
|
|
4136
|
+
const spacing = Number.parseFloat(computed.letterSpacing) || 0;
|
|
4137
|
+
return (value) => context.measureText(value).width + spacing * value.length;
|
|
4138
|
+
}
|
|
4139
|
+
/** Largest `n` in `[0, max]` for which `fits(n)` holds. */
|
|
4140
|
+
function largestFitting(max, fits) {
|
|
4141
|
+
let low = 0;
|
|
4142
|
+
let high = max;
|
|
4143
|
+
while (low < high) {
|
|
4144
|
+
const mid = Math.ceil((low + high) / 2);
|
|
4145
|
+
if (fits(mid)) low = mid;
|
|
4146
|
+
else high = mid - 1;
|
|
4147
|
+
}
|
|
4148
|
+
return low;
|
|
4149
|
+
}
|
|
4150
|
+
function truncateToWidth(text, side, ellipsis, available, measure) {
|
|
4151
|
+
if (measure(text) <= available) return text;
|
|
4152
|
+
const chars = Array.from(text);
|
|
4153
|
+
if (side === "end") {
|
|
4154
|
+
const keep = largestFitting(chars.length, (n) => measure(chars.slice(0, n).join("") + ellipsis) <= available);
|
|
4155
|
+
return chars.slice(0, keep).join("") + ellipsis;
|
|
4156
|
+
}
|
|
4157
|
+
if (side === "start") {
|
|
4158
|
+
const keep = largestFitting(chars.length, (n) => measure(ellipsis + chars.slice(chars.length - n).join("")) <= available);
|
|
4159
|
+
return ellipsis + chars.slice(chars.length - keep).join("");
|
|
4160
|
+
}
|
|
4161
|
+
if (side === "startEnd") {
|
|
4162
|
+
const keep = largestFitting(Math.floor(chars.length / 2), (n) => {
|
|
4163
|
+
const head = chars.slice(0, n).join("");
|
|
4164
|
+
const tail = chars.slice(chars.length - n).join("");
|
|
4165
|
+
return measure(head + ellipsis + tail) <= available;
|
|
4166
|
+
});
|
|
4167
|
+
if (keep === 0) return ellipsis;
|
|
4168
|
+
return chars.slice(0, keep).join("") + ellipsis + chars.slice(chars.length - keep).join("");
|
|
4169
|
+
}
|
|
4170
|
+
const span = largestFitting(chars.length, (n) => {
|
|
4171
|
+
const start = Math.floor((chars.length - n) / 2);
|
|
4172
|
+
return measure(ellipsis + chars.slice(start, start + n).join("") + ellipsis) <= available;
|
|
4173
|
+
});
|
|
4174
|
+
if (span === 0) return ellipsis;
|
|
4175
|
+
const start = Math.floor((chars.length - span) / 2);
|
|
4176
|
+
return ellipsis + chars.slice(start, start + span).join("") + ellipsis;
|
|
4177
|
+
}
|
|
4178
|
+
/**
|
|
4179
|
+
* TextTruncate — drops characters from the part of a string that identifies it
|
|
4180
|
+
* least.
|
|
4181
|
+
*
|
|
4182
|
+
* CSS can only cut the end. That is the wrong end for the strings analytics
|
|
4183
|
+
* shows most: two URLs that differ in their query string, two ids that share a
|
|
4184
|
+
* prefix, a stack frame whose filename is at the tail. This measures the real
|
|
4185
|
+
* text in the real font against the real available width and cuts where the
|
|
4186
|
+
* caller says.
|
|
4187
|
+
*
|
|
4188
|
+
* The full string stays in the accessibility tree and in `title`, so
|
|
4189
|
+
* truncation never costs the reader information — only space.
|
|
4190
|
+
*
|
|
4191
|
+
* @example
|
|
4192
|
+
* ```tsx
|
|
4193
|
+
* <TextTruncate text={event.url} truncation="startEnd" />
|
|
4194
|
+
* ```
|
|
4195
|
+
*/
|
|
4196
|
+
function TextTruncate({ text, truncation = "startEnd", ellipsis = "…", width, children, className }) {
|
|
4197
|
+
const ref = (0, react.useRef)(null);
|
|
4198
|
+
const [available, setAvailable] = (0, react.useState)(width !== null && width !== void 0 ? width : null);
|
|
4199
|
+
useIsomorphicLayoutEffect(() => {
|
|
4200
|
+
if (width !== void 0) {
|
|
4201
|
+
setAvailable(width);
|
|
4202
|
+
return;
|
|
4203
|
+
}
|
|
4204
|
+
const element = ref.current;
|
|
4205
|
+
if (!element || typeof ResizeObserver === "undefined") return;
|
|
4206
|
+
const observer = new ResizeObserver((entries) => {
|
|
4207
|
+
const entry = entries[0];
|
|
4208
|
+
if (entry) setAvailable(entry.contentRect.width);
|
|
4209
|
+
});
|
|
4210
|
+
observer.observe(element);
|
|
4211
|
+
setAvailable(element.getBoundingClientRect().width);
|
|
4212
|
+
return () => observer.disconnect();
|
|
4213
|
+
}, [width]);
|
|
4214
|
+
const [rendered, setRendered] = (0, react.useState)(text);
|
|
4215
|
+
useIsomorphicLayoutEffect(() => {
|
|
4216
|
+
const element = ref.current;
|
|
4217
|
+
if (!element || available === null || available <= 0) {
|
|
4218
|
+
setRendered(text);
|
|
4219
|
+
return;
|
|
4220
|
+
}
|
|
4221
|
+
const measure = createMeasurer(element);
|
|
4222
|
+
if (!measure) {
|
|
4223
|
+
setRendered(text);
|
|
4224
|
+
return;
|
|
4225
|
+
}
|
|
4226
|
+
setRendered(truncateToWidth(text, truncation, ellipsis, available, measure));
|
|
4227
|
+
}, [
|
|
4228
|
+
text,
|
|
4229
|
+
truncation,
|
|
4230
|
+
ellipsis,
|
|
4231
|
+
available
|
|
4232
|
+
]);
|
|
4233
|
+
const truncated = rendered !== text;
|
|
4234
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4235
|
+
ref,
|
|
4236
|
+
className: cn("block w-full overflow-hidden whitespace-nowrap", className),
|
|
4237
|
+
title: truncated ? text : void 0,
|
|
4238
|
+
"data-opt-id": "Y6BGX",
|
|
4239
|
+
"data-opt-slug": "text-truncate.TextTruncate",
|
|
4240
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4241
|
+
"aria-hidden": truncated ? "true" : void 0,
|
|
4242
|
+
children: children ? children(rendered) : rendered
|
|
4243
|
+
}), truncated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4244
|
+
className: "sr-only",
|
|
4245
|
+
children: text
|
|
4246
|
+
})]
|
|
4247
|
+
});
|
|
4248
|
+
}
|
|
4249
|
+
//#endregion
|
|
3870
4250
|
Object.defineProperty(exports, "Alert", {
|
|
3871
4251
|
enumerable: true,
|
|
3872
4252
|
get: function() {
|
|
@@ -4047,12 +4427,24 @@ Object.defineProperty(exports, "EmptyState", {
|
|
|
4047
4427
|
return EmptyState;
|
|
4048
4428
|
}
|
|
4049
4429
|
});
|
|
4430
|
+
Object.defineProperty(exports, "FIELD_TYPE_TOKENS", {
|
|
4431
|
+
enumerable: true,
|
|
4432
|
+
get: function() {
|
|
4433
|
+
return FIELD_TYPE_TOKENS;
|
|
4434
|
+
}
|
|
4435
|
+
});
|
|
4050
4436
|
Object.defineProperty(exports, "FieldMessages", {
|
|
4051
4437
|
enumerable: true,
|
|
4052
4438
|
get: function() {
|
|
4053
4439
|
return FieldMessages;
|
|
4054
4440
|
}
|
|
4055
4441
|
});
|
|
4442
|
+
Object.defineProperty(exports, "FieldToken", {
|
|
4443
|
+
enumerable: true,
|
|
4444
|
+
get: function() {
|
|
4445
|
+
return FieldToken;
|
|
4446
|
+
}
|
|
4447
|
+
});
|
|
4056
4448
|
Object.defineProperty(exports, "FormCheckbox", {
|
|
4057
4449
|
enumerable: true,
|
|
4058
4450
|
get: function() {
|
|
@@ -4227,6 +4619,12 @@ Object.defineProperty(exports, "FormTextarea", {
|
|
|
4227
4619
|
return FormTextarea;
|
|
4228
4620
|
}
|
|
4229
4621
|
});
|
|
4622
|
+
Object.defineProperty(exports, "Highlight", {
|
|
4623
|
+
enumerable: true,
|
|
4624
|
+
get: function() {
|
|
4625
|
+
return Highlight;
|
|
4626
|
+
}
|
|
4627
|
+
});
|
|
4230
4628
|
Object.defineProperty(exports, "IconPicker", {
|
|
4231
4629
|
enumerable: true,
|
|
4232
4630
|
get: function() {
|
|
@@ -4629,6 +5027,12 @@ Object.defineProperty(exports, "TagInput", {
|
|
|
4629
5027
|
return TagInput;
|
|
4630
5028
|
}
|
|
4631
5029
|
});
|
|
5030
|
+
Object.defineProperty(exports, "TextTruncate", {
|
|
5031
|
+
enumerable: true,
|
|
5032
|
+
get: function() {
|
|
5033
|
+
return TextTruncate;
|
|
5034
|
+
}
|
|
5035
|
+
});
|
|
4632
5036
|
Object.defineProperty(exports, "ToolbarButton", {
|
|
4633
5037
|
enumerable: true,
|
|
4634
5038
|
get: function() {
|
|
@@ -4725,6 +5129,12 @@ Object.defineProperty(exports, "koStarRatingLabels", {
|
|
|
4725
5129
|
return koStarRatingLabels;
|
|
4726
5130
|
}
|
|
4727
5131
|
});
|
|
5132
|
+
Object.defineProperty(exports, "resolveFieldType", {
|
|
5133
|
+
enumerable: true,
|
|
5134
|
+
get: function() {
|
|
5135
|
+
return resolveFieldType;
|
|
5136
|
+
}
|
|
5137
|
+
});
|
|
4728
5138
|
Object.defineProperty(exports, "useControlledState", {
|
|
4729
5139
|
enumerable: true,
|
|
4730
5140
|
get: function() {
|