@jsenv/navi 0.25.9 → 0.26.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/jsenv_navi.js +119 -21
- package/dist/jsenv_navi.js.map +16 -7
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -21346,6 +21346,26 @@ const TextAnchor = ({
|
|
|
21346
21346
|
}) => {
|
|
21347
21347
|
import.meta.css = [css$z, "@jsenv/navi/src/text/text_anchor.jsx"];
|
|
21348
21348
|
const anchorRef = useRef();
|
|
21349
|
+
const setTopOffset = (childEl, topOffset) => {
|
|
21350
|
+
// position:relative + top shifts the element visually.
|
|
21351
|
+
// marginTop: -topOffset makes the layout box follow the visual position, so any container
|
|
21352
|
+
// (button, link, box…) computes its own padding/border/height based on the real final position
|
|
21353
|
+
// rather than the original unshifted one. This means a badge inside a button will symmetrically
|
|
21354
|
+
// expand the button height instead of overflowing or being clipped.
|
|
21355
|
+
// marginBottom: topOffset compensates the marginTop so the line height stays unchanged —
|
|
21356
|
+
// the shift is purely a repositioning, not an inflation of the line.
|
|
21357
|
+
if (!topOffset) {
|
|
21358
|
+
childEl.style.position = "";
|
|
21359
|
+
childEl.style.top = "";
|
|
21360
|
+
childEl.style.marginTop = "";
|
|
21361
|
+
childEl.style.marginBottom = "";
|
|
21362
|
+
return;
|
|
21363
|
+
}
|
|
21364
|
+
childEl.style.position = "relative";
|
|
21365
|
+
childEl.style.top = `${topOffset}px`;
|
|
21366
|
+
childEl.style.marginTop = `${-topOffset}px`;
|
|
21367
|
+
childEl.style.marginBottom = `${topOffset}px`;
|
|
21368
|
+
};
|
|
21349
21369
|
useLayoutEffect(() => {
|
|
21350
21370
|
const anchorEl = anchorRef.current;
|
|
21351
21371
|
const childEl = childRef.current;
|
|
@@ -21359,32 +21379,16 @@ const TextAnchor = ({
|
|
|
21359
21379
|
if (parentDisplay !== "inline" && parentDisplay !== "inline-block" && parentDisplay !== "block") {
|
|
21360
21380
|
// we must hide the anchor otherwise it would affect layout without providing any benefit (would trigger flex gap for instance)
|
|
21361
21381
|
anchorEl.setAttribute("hidden", "");
|
|
21362
|
-
|
|
21363
|
-
|
|
21382
|
+
setTopOffset(childEl, 0);
|
|
21383
|
+
return;
|
|
21364
21384
|
}
|
|
21385
|
+
anchorEl.removeAttribute("hidden");
|
|
21365
21386
|
const topOffset = computeTopOffset({
|
|
21366
21387
|
anchorEl,
|
|
21367
21388
|
childEl,
|
|
21368
21389
|
textAnchor
|
|
21369
21390
|
});
|
|
21370
|
-
|
|
21371
|
-
// position:relative + top shifts the element visually.
|
|
21372
|
-
// marginTop: -topOffset makes the layout box follow the visual position, so any container
|
|
21373
|
-
// (button, link, box…) computes its own padding/border/height based on the real final position
|
|
21374
|
-
// rather than the original unshifted one. This means a badge inside a button will symmetrically
|
|
21375
|
-
// expand the button height instead of overflowing or being clipped.
|
|
21376
|
-
// marginBottom: topOffset compensates the marginTop so the line height stays unchanged —
|
|
21377
|
-
// the shift is purely a repositioning, not an inflation of the line.
|
|
21378
|
-
childEl.style.position = "relative";
|
|
21379
|
-
childEl.style.top = `${topOffset}px`;
|
|
21380
|
-
childEl.style.marginTop = `${-topOffset}px`;
|
|
21381
|
-
childEl.style.marginBottom = `${topOffset}px`;
|
|
21382
|
-
} else {
|
|
21383
|
-
childEl.style.position = "";
|
|
21384
|
-
childEl.style.top = "";
|
|
21385
|
-
childEl.style.marginTop = "";
|
|
21386
|
-
childEl.style.marginBottom = "";
|
|
21387
|
-
}
|
|
21391
|
+
setTopOffset(childEl, topOffset);
|
|
21388
21392
|
}, [textAnchor, textKey, textSize, lineLayout?.size, lineLayout?.verticalAlign]);
|
|
21389
21393
|
return jsxs(Fragment, {
|
|
21390
21394
|
children: [children, jsx("span", {
|
|
@@ -36394,6 +36398,100 @@ const CodeBox = ({
|
|
|
36394
36398
|
});
|
|
36395
36399
|
};
|
|
36396
36400
|
|
|
36401
|
+
/*
|
|
36402
|
+
* Technical note: although the component is named Interpolate and its primary
|
|
36403
|
+
* use-case is text, it can render any mix of strings and JSX elements — 99% of
|
|
36404
|
+
* the time it is used for text though.
|
|
36405
|
+
*
|
|
36406
|
+
* Why use Interpolate instead of plain JSX?
|
|
36407
|
+
*
|
|
36408
|
+
* Without Interpolate, the sentence is scattered across JSX expressions:
|
|
36409
|
+
*
|
|
36410
|
+
* ```jsx
|
|
36411
|
+
* // harder to read — the full sentence is not visible at once
|
|
36412
|
+
* // cannot be used as an i18n key
|
|
36413
|
+
* Données limitées à <Text bold>{radius} km</Text> autour de
|
|
36414
|
+
* {zoneName || "votre zone"}.
|
|
36415
|
+
* ```
|
|
36416
|
+
*
|
|
36417
|
+
* With Interpolate, the full sentence is visible in one place:
|
|
36418
|
+
*
|
|
36419
|
+
* ```jsx
|
|
36420
|
+
* // readable — the sentence reads as prose
|
|
36421
|
+
* // i18n-ready — the template string is a plain JS-free key
|
|
36422
|
+
* <Interpolate radiusKm={<Text bold>{radius} km</Text>} zoneName={zoneName || "votre zone"}>
|
|
36423
|
+
* Données limitées à [radiusKm] autour de [zoneName].
|
|
36424
|
+
* </Interpolate>
|
|
36425
|
+
* ```
|
|
36426
|
+
*
|
|
36427
|
+
* Why [key] syntax was chosen for placeholders:
|
|
36428
|
+
*
|
|
36429
|
+
* {} / ${} / {{}} — interpreted by JSX; using them would force wrapping the
|
|
36430
|
+
* whole string in an expression, defeating the readability
|
|
36431
|
+
* goal.
|
|
36432
|
+
*
|
|
36433
|
+
* %key% — common in sprintf-style libraries, but the doubled %% hurts
|
|
36434
|
+
* readability. It also carries the implicit expectation of
|
|
36435
|
+
* format specifiers (cast to string/number, padding…) that
|
|
36436
|
+
* this component does not support, which would mislead readers.
|
|
36437
|
+
*
|
|
36438
|
+
* :key: — visually clean, but the colon conflicts with punctuation.
|
|
36439
|
+
* Compare: "Hello :name:. How are you?"
|
|
36440
|
+
* vs "Hello [name]. How are you?"
|
|
36441
|
+
* The period after :name: is ambiguous at a glance.
|
|
36442
|
+
*
|
|
36443
|
+
* <key> — not possible; JSX treats it as an opening tag.
|
|
36444
|
+
*/
|
|
36445
|
+
|
|
36446
|
+
/**
|
|
36447
|
+
* Renders a template string with [key] placeholders replaced by props.
|
|
36448
|
+
* Replacement values can be strings or JSX elements.
|
|
36449
|
+
* Returns a plain string when all replacements are strings, a fragment otherwise.
|
|
36450
|
+
*
|
|
36451
|
+
* Keeps the full sentence readable in one place and makes the string
|
|
36452
|
+
* i18n-ready, since the template contains no JSX expressions.
|
|
36453
|
+
*
|
|
36454
|
+
* @example
|
|
36455
|
+
* <Interpolate radiusKm={<Text bold>50 km</Text>} zoneName="votre zone">
|
|
36456
|
+
* Données limitées à [radiusKm] autour de [zoneName].
|
|
36457
|
+
* </Interpolate>
|
|
36458
|
+
*/
|
|
36459
|
+
const Interpolate = ({
|
|
36460
|
+
children,
|
|
36461
|
+
...replacements
|
|
36462
|
+
}) => {
|
|
36463
|
+
return interpolateText(children, replacements);
|
|
36464
|
+
};
|
|
36465
|
+
|
|
36466
|
+
/**
|
|
36467
|
+
* Interpolates a template string, replacing [key] placeholders with values.
|
|
36468
|
+
* Values can be strings or JSX elements. Returns a plain string when all
|
|
36469
|
+
* replacements are strings, or a JSX fragment otherwise.
|
|
36470
|
+
*/
|
|
36471
|
+
const interpolateText = (template, replacements) => {
|
|
36472
|
+
const parts = template.split(/(\[[^\]]+\])/);
|
|
36473
|
+
let hasVnode = false;
|
|
36474
|
+
const resolved = [];
|
|
36475
|
+
for (const part of parts) {
|
|
36476
|
+
const match = part.match(/^\[([^\]]+)\]$/);
|
|
36477
|
+
if (!match) {
|
|
36478
|
+
resolved.push(part);
|
|
36479
|
+
continue;
|
|
36480
|
+
}
|
|
36481
|
+
const value = replacements[match[1]] ?? part;
|
|
36482
|
+
if (value !== null && typeof value === "object") {
|
|
36483
|
+
hasVnode = true;
|
|
36484
|
+
}
|
|
36485
|
+
resolved.push(value);
|
|
36486
|
+
}
|
|
36487
|
+
if (!hasVnode) {
|
|
36488
|
+
return resolved.join("");
|
|
36489
|
+
}
|
|
36490
|
+
return jsx(Fragment, {
|
|
36491
|
+
children: resolved
|
|
36492
|
+
});
|
|
36493
|
+
};
|
|
36494
|
+
|
|
36397
36495
|
const navigator = typeof window === "undefined" ? undefined : window.navigator;
|
|
36398
36496
|
const browserLang =
|
|
36399
36497
|
typeof navigator !== "undefined"
|
|
@@ -37543,5 +37641,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
37543
37641
|
})
|
|
37544
37642
|
});
|
|
37545
37643
|
|
|
37546
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, Box, Button, ButtonCopyToClipboard, Caption, CheckSvg, Checkbox, CheckboxList, CloseSvg, Code, Col, Colgroup, ConstructionSvg, Details, Dialog, DialogLayout, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemFooter, ListItemGroup, ListItemHeader, Loading, MessageBox, Meter, Nav, NaviDebug, Paragraph, Popover, Quantity, QuantityIntl, Radio, RadioList, Route, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectionContext, Separator, SettingsSvg, SidePanel, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, Thead, Title, Tr, UITransition, UserSvg, ViewportLayout, actionIntegratedVia, actionRunEffect, addCustomMessage, applySearch, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createIntl, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, enableDebugActions, enableDebugOnDocumentLoading, filterTableSelection, forwardActionRequested, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, localStorageSignal, navBack, navForward, navTo, openCallout, rawUrlPart, reload, removeCustomMessage, requestAction, requestListClose, requestListOpen, rerunActions, resource, route, routeAction, setBaseUrl, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, syncOwnedResourceToSignals, syncResourceToSignals, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, useRouteStatus, useRunOnMount, useSearchText, useSelectRequestClose, useSelectableElement, useSelectionController, useSidePanelClose, useSignalSync, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage, windowWidthSignal };
|
|
37644
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, Box, Button, ButtonCopyToClipboard, Caption, CheckSvg, Checkbox, CheckboxList, CloseSvg, Code, Col, Colgroup, ConstructionSvg, Details, Dialog, DialogLayout, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemFooter, ListItemGroup, ListItemHeader, Loading, MessageBox, Meter, Nav, NaviDebug, Paragraph, Popover, Quantity, QuantityIntl, Radio, RadioList, Route, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectionContext, Separator, SettingsSvg, SidePanel, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, Thead, Title, Tr, UITransition, UserSvg, ViewportLayout, actionIntegratedVia, actionRunEffect, addCustomMessage, applySearch, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createIntl, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, enableDebugActions, enableDebugOnDocumentLoading, filterTableSelection, forwardActionRequested, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, localStorageSignal, navBack, navForward, navTo, openCallout, rawUrlPart, reload, removeCustomMessage, requestAction, requestListClose, requestListOpen, rerunActions, resource, route, routeAction, setBaseUrl, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, syncOwnedResourceToSignals, syncResourceToSignals, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, useRouteStatus, useRunOnMount, useSearchText, useSelectRequestClose, useSelectableElement, useSelectionController, useSidePanelClose, useSignalSync, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage, windowWidthSignal };
|
|
37547
37645
|
//# sourceMappingURL=jsenv_navi.js.map
|