@aglyn/shared-ui-jsx 1.0.0-beta.143
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/LICENSE +201 -0
- package/README.md +7 -0
- package/package.json +63 -0
- package/src/index.d.ts +48 -0
- package/src/index.js +179 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/aglyn-text.d.ts +86 -0
- package/src/lib/components/aglyn-text.js +44 -0
- package/src/lib/components/aglyn-text.js.map +1 -0
- package/src/lib/components/app-link.d.ts +74 -0
- package/src/lib/components/app-link.js +139 -0
- package/src/lib/components/app-link.js.map +1 -0
- package/src/lib/components/aspect-ratio.d.ts +59 -0
- package/src/lib/components/aspect-ratio.js +153 -0
- package/src/lib/components/aspect-ratio.js.map +1 -0
- package/src/lib/components/background-image.component.d.ts +30 -0
- package/src/lib/components/background-image.component.js +42 -0
- package/src/lib/components/background-image.component.js.map +1 -0
- package/src/lib/components/card-columns.d.ts +86 -0
- package/src/lib/components/card-columns.js +148 -0
- package/src/lib/components/card-columns.js.map +1 -0
- package/src/lib/components/card-display.d.ts +36 -0
- package/src/lib/components/card-display.js +158 -0
- package/src/lib/components/card-display.js.map +1 -0
- package/src/lib/components/card-list-item.d.ts +35 -0
- package/src/lib/components/card-list-item.js +137 -0
- package/src/lib/components/card-list-item.js.map +1 -0
- package/src/lib/components/children-function-prop.d.ts +25 -0
- package/src/lib/components/children-function-prop.js +29 -0
- package/src/lib/components/children-function-prop.js.map +1 -0
- package/src/lib/components/confirmation-provider.component.d.ts +19 -0
- package/src/lib/components/confirmation-provider.component.js +83 -0
- package/src/lib/components/confirmation-provider.component.js.map +1 -0
- package/src/lib/components/container.d.ts +25 -0
- package/src/lib/components/container.js +62 -0
- package/src/lib/components/container.js.map +1 -0
- package/src/lib/components/data-table.component.d.ts +54 -0
- package/src/lib/components/data-table.component.js +211 -0
- package/src/lib/components/data-table.component.js.map +1 -0
- package/src/lib/components/dialog-confirm.d.ts +36 -0
- package/src/lib/components/dialog-confirm.js +74 -0
- package/src/lib/components/dialog-confirm.js.map +1 -0
- package/src/lib/components/ellipsis-pulse.component.d.ts +22 -0
- package/src/lib/components/ellipsis-pulse.component.js +51 -0
- package/src/lib/components/ellipsis-pulse.component.js.map +1 -0
- package/src/lib/components/emotion-cache-provider.d.ts +31 -0
- package/src/lib/components/emotion-cache-provider.js +40 -0
- package/src/lib/components/emotion-cache-provider.js.map +1 -0
- package/src/lib/components/empty-state.component.d.ts +63 -0
- package/src/lib/components/empty-state.component.js +214 -0
- package/src/lib/components/empty-state.component.js.map +1 -0
- package/src/lib/components/error-boundary.component.d.ts +28 -0
- package/src/lib/components/error-boundary.component.js +86 -0
- package/src/lib/components/error-boundary.component.js.map +1 -0
- package/src/lib/components/grid-buttons.d.ts +26 -0
- package/src/lib/components/grid-buttons.js +45 -0
- package/src/lib/components/grid-buttons.js.map +1 -0
- package/src/lib/components/grid-items.d.ts +103 -0
- package/src/lib/components/grid-items.js +336 -0
- package/src/lib/components/grid-items.js.map +1 -0
- package/src/lib/components/grid-list.d.ts +37 -0
- package/src/lib/components/grid-list.js +156 -0
- package/src/lib/components/grid-list.js.map +1 -0
- package/src/lib/components/help-tip.component.d.ts +30 -0
- package/src/lib/components/help-tip.component.js +139 -0
- package/src/lib/components/help-tip.component.js.map +1 -0
- package/src/lib/components/link-navigation-reporter.d.ts +24 -0
- package/src/lib/components/link-navigation-reporter.js +64 -0
- package/src/lib/components/link-navigation-reporter.js.map +1 -0
- package/src/lib/components/list-pagination.component.d.ts +57 -0
- package/src/lib/components/list-pagination.component.js +90 -0
- package/src/lib/components/list-pagination.component.js.map +1 -0
- package/src/lib/components/list-table.component.d.ts +155 -0
- package/src/lib/components/list-table.component.js +369 -0
- package/src/lib/components/list-table.component.js.map +1 -0
- package/src/lib/components/loading-layout-app.component.d.ts +35 -0
- package/src/lib/components/loading-layout-app.component.js +42 -0
- package/src/lib/components/loading-layout-app.component.js.map +1 -0
- package/src/lib/components/loading-modal-overlay.d.ts +30 -0
- package/src/lib/components/loading-modal-overlay.js +156 -0
- package/src/lib/components/loading-modal-overlay.js.map +1 -0
- package/src/lib/components/loading-modal.d.ts +19 -0
- package/src/lib/components/loading-modal.js +113 -0
- package/src/lib/components/loading-modal.js.map +1 -0
- package/src/lib/components/loading-text.component.d.ts +21 -0
- package/src/lib/components/loading-text.component.js +40 -0
- package/src/lib/components/loading-text.component.js.map +1 -0
- package/src/lib/components/mdi-icon/index.d.ts +2 -0
- package/src/lib/components/mdi-icon/index.js +4 -0
- package/src/lib/components/mdi-icon/index.js.map +1 -0
- package/src/lib/components/mdi-icon/md-icon-stack.d.ts +31 -0
- package/src/lib/components/mdi-icon/md-icon-stack.js +101 -0
- package/src/lib/components/mdi-icon/md-icon-stack.js.map +1 -0
- package/src/lib/components/mdi-icon/md-icon.d.ts +32 -0
- package/src/lib/components/mdi-icon/md-icon.js +147 -0
- package/src/lib/components/mdi-icon/md-icon.js.map +1 -0
- package/src/lib/components/mdi-icon/mdi-icon-from-id.d.ts +23 -0
- package/src/lib/components/mdi-icon/mdi-icon-from-id.js +35 -0
- package/src/lib/components/mdi-icon/mdi-icon-from-id.js.map +1 -0
- package/src/lib/components/mdi-icon/mdi-icon.d.ts +24 -0
- package/src/lib/components/mdi-icon/mdi-icon.js +46 -0
- package/src/lib/components/mdi-icon/mdi-icon.js.map +1 -0
- package/src/lib/components/measured-figures.component.d.ts +64 -0
- package/src/lib/components/measured-figures.component.js +161 -0
- package/src/lib/components/measured-figures.component.js.map +1 -0
- package/src/lib/components/menu.d.ts +45 -0
- package/src/lib/components/menu.js +229 -0
- package/src/lib/components/menu.js.map +1 -0
- package/src/lib/components/mui-shadow-dom.d.ts +38 -0
- package/src/lib/components/mui-shadow-dom.js +161 -0
- package/src/lib/components/mui-shadow-dom.js.map +1 -0
- package/src/lib/components/navigation-drawer.component.d.ts +31 -0
- package/src/lib/components/navigation-drawer.component.js +76 -0
- package/src/lib/components/navigation-drawer.component.js.map +1 -0
- package/src/lib/components/navigation-intent.d.ts +18 -0
- package/src/lib/components/navigation-intent.js +56 -0
- package/src/lib/components/navigation-intent.js.map +1 -0
- package/src/lib/components/navigation-view/index.d.ts +18 -0
- package/src/lib/components/navigation-view/index.js +19 -0
- package/src/lib/components/navigation-view/index.js.map +1 -0
- package/src/lib/components/navigation-view/navigation-view.d.ts +35 -0
- package/src/lib/components/navigation-view/navigation-view.js +175 -0
- package/src/lib/components/navigation-view/navigation-view.js.map +1 -0
- package/src/lib/components/next-link.d.ts +27 -0
- package/src/lib/components/next-link.js +88 -0
- package/src/lib/components/next-link.js.map +1 -0
- package/src/lib/components/popper-styled.component.d.ts +25 -0
- package/src/lib/components/popper-styled.component.js +129 -0
- package/src/lib/components/popper-styled.component.js.map +1 -0
- package/src/lib/components/quota-readout.component.d.ts +69 -0
- package/src/lib/components/quota-readout.component.js +52 -0
- package/src/lib/components/quota-readout.component.js.map +1 -0
- package/src/lib/components/resizeable-stack.d.ts +4 -0
- package/src/lib/components/resizeable-stack.js +23 -0
- package/src/lib/components/resizeable-stack.js.map +1 -0
- package/src/lib/components/row-actions-menu.component.d.ts +53 -0
- package/src/lib/components/row-actions-menu.component.js +132 -0
- package/src/lib/components/row-actions-menu.component.js.map +1 -0
- package/src/lib/components/ruler-guides.component.d.ts +35 -0
- package/src/lib/components/ruler-guides.component.js +166 -0
- package/src/lib/components/ruler-guides.component.js.map +1 -0
- package/src/lib/components/sandbox-frame.d.ts +42 -0
- package/src/lib/components/sandbox-frame.js +122 -0
- package/src/lib/components/sandbox-frame.js.map +1 -0
- package/src/lib/components/scroll-reaction.d.ts +59 -0
- package/src/lib/components/scroll-reaction.js +43 -0
- package/src/lib/components/scroll-reaction.js.map +1 -0
- package/src/lib/components/scroll-table.component.d.ts +124 -0
- package/src/lib/components/scroll-table.component.js +103 -0
- package/src/lib/components/scroll-table.component.js.map +1 -0
- package/src/lib/components/shadow-dom/index.d.ts +18 -0
- package/src/lib/components/shadow-dom/index.js +19 -0
- package/src/lib/components/shadow-dom/index.js.map +1 -0
- package/src/lib/components/shadow-dom/shadow-dom.d.ts +42 -0
- package/src/lib/components/shadow-dom/shadow-dom.js +123 -0
- package/src/lib/components/shadow-dom/shadow-dom.js.map +1 -0
- package/src/lib/components/splash-screen.d.ts +33 -0
- package/src/lib/components/splash-screen.js +105 -0
- package/src/lib/components/splash-screen.js.map +1 -0
- package/src/lib/components/sr-only.d.ts +20 -0
- package/src/lib/components/sr-only.js +25 -0
- package/src/lib/components/sr-only.js.map +1 -0
- package/src/lib/components/status-screen-plain.component.d.ts +27 -0
- package/src/lib/components/status-screen-plain.component.js +178 -0
- package/src/lib/components/status-screen-plain.component.js.map +1 -0
- package/src/lib/components/usage-meter.component.d.ts +30 -0
- package/src/lib/components/usage-meter.component.js +92 -0
- package/src/lib/components/usage-meter.component.js.map +1 -0
- package/src/lib/components/variable-text-field.component.d.ts +50 -0
- package/src/lib/components/variable-text-field.component.js +188 -0
- package/src/lib/components/variable-text-field.component.js.map +1 -0
- package/src/lib/components/zoomable-panning-component/index.d.ts +1 -0
- package/src/lib/components/zoomable-panning-component/index.js +3 -0
- package/src/lib/components/zoomable-panning-component/index.js.map +1 -0
- package/src/lib/components/zoomable-panning-component/util.d.ts +58 -0
- package/src/lib/components/zoomable-panning-component/util.js +114 -0
- package/src/lib/components/zoomable-panning-component/util.js.map +1 -0
- package/src/lib/components/zoomable-panning-component/zoomable-panning-component.d.ts +132 -0
- package/src/lib/components/zoomable-panning-component/zoomable-panning-component.js +728 -0
- package/src/lib/components/zoomable-panning-component/zoomable-panning-component.js.map +1 -0
- package/src/lib/const/aglyn-besigner-logo-full.d.ts +39 -0
- package/src/lib/const/aglyn-besigner-logo-full.js +146 -0
- package/src/lib/const/aglyn-besigner-logo-full.js.map +1 -0
- package/src/lib/const/aglyn-console-logo-full.d.ts +34 -0
- package/src/lib/const/aglyn-console-logo-full.js +142 -0
- package/src/lib/const/aglyn-console-logo-full.js.map +1 -0
- package/src/lib/const/aglyn-logo-class-keys.d.ts +30 -0
- package/src/lib/const/aglyn-logo-class-keys.js +32 -0
- package/src/lib/const/aglyn-logo-class-keys.js.map +1 -0
- package/src/lib/const/aglyn-logo-full.d.ts +29 -0
- package/src/lib/const/aglyn-logo-full.js +111 -0
- package/src/lib/const/aglyn-logo-full.js.map +1 -0
- package/src/lib/const/list-filter.d.ts +260 -0
- package/src/lib/const/list-filter.js +409 -0
- package/src/lib/const/list-filter.js.map +1 -0
- package/src/lib/const/prebuilt-components.d.ts +17 -0
- package/src/lib/const/prebuilt-components.js +22 -0
- package/src/lib/const/prebuilt-components.js.map +1 -0
- package/src/lib/const/svg-icons.d.ts +75 -0
- package/src/lib/const/svg-icons.js +313 -0
- package/src/lib/const/svg-icons.js.map +1 -0
- package/src/lib/const/table-pagination.d.ts +106 -0
- package/src/lib/const/table-pagination.js +106 -0
- package/src/lib/const/table-pagination.js.map +1 -0
- package/src/lib/contexts/confirmation.context.d.ts +996 -0
- package/src/lib/contexts/confirmation.context.js +49 -0
- package/src/lib/contexts/confirmation.context.js.map +1 -0
- package/src/lib/contexts/loading.context.d.ts +93 -0
- package/src/lib/contexts/loading.context.js +126 -0
- package/src/lib/contexts/loading.context.js.map +1 -0
- package/src/lib/hocs/create-hoc-with-context-consumer.d.ts +36 -0
- package/src/lib/hocs/create-hoc-with-context-consumer.js +44 -0
- package/src/lib/hocs/create-hoc-with-context-consumer.js.map +1 -0
- package/src/lib/hocs/with-hoc.d.ts +32 -0
- package/src/lib/hocs/with-hoc.js +37 -0
- package/src/lib/hocs/with-hoc.js.map +1 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icon.d.ts +20 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icon.js +48 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icon.js.map +1 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icons-fuzzy.d.ts +26 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icons-fuzzy.js +73 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icons-fuzzy.js.map +1 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icons.d.ts +19 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icons.js +49 -0
- package/src/lib/hooks/mdi-icon/use-mdi-icons.js.map +1 -0
- package/src/lib/hooks/router-events.d.ts +56 -0
- package/src/lib/hooks/router-events.js +88 -0
- package/src/lib/hooks/router-events.js.map +1 -0
- package/src/lib/hooks/use-async-effect.d.ts +24 -0
- package/src/lib/hooks/use-async-effect.js +44 -0
- package/src/lib/hooks/use-async-effect.js.map +1 -0
- package/src/lib/hooks/use-callback-param-ref.d.ts +19 -0
- package/src/lib/hooks/use-callback-param-ref.js +29 -0
- package/src/lib/hooks/use-callback-param-ref.js.map +1 -0
- package/src/lib/hooks/use-id.d.ts +21 -0
- package/src/lib/hooks/use-id.js +28 -0
- package/src/lib/hooks/use-id.js.map +1 -0
- package/src/lib/hooks/use-isomorphic-layout-effect.d.ts +19 -0
- package/src/lib/hooks/use-isomorphic-layout-effect.js +20 -0
- package/src/lib/hooks/use-isomorphic-layout-effect.js.map +1 -0
- package/src/lib/hooks/use-merge-refs.d.ts +38 -0
- package/src/lib/hooks/use-merge-refs.js +52 -0
- package/src/lib/hooks/use-merge-refs.js.map +1 -0
- package/src/lib/hooks/use-subscribable.d.ts +29 -0
- package/src/lib/hooks/use-subscribable.js +50 -0
- package/src/lib/hooks/use-subscribable.js.map +1 -0
- package/src/lib/types.d.ts +18 -0
- package/src/lib/types.js +18 -0
- package/src/lib/types.js.map +1 -0
- package/src/lib/utils/make-link-elements.d.ts +24 -0
- package/src/lib/utils/make-link-elements.js +32 -0
- package/src/lib/utils/make-link-elements.js.map +1 -0
- package/src/lib/utils/make-meta-elements.d.ts +24 -0
- package/src/lib/utils/make-meta-elements.js +32 -0
- package/src/lib/utils/make-meta-elements.js.map +1 -0
- package/src/lib/utils/scroll-overflow.d.ts +120 -0
- package/src/lib/utils/scroll-overflow.js +115 -0
- package/src/lib/utils/scroll-overflow.js.map +1 -0
- package/src/lib/utils/vendor.d.ts +17 -0
- package/src/lib/utils/vendor.js +18 -0
- package/src/lib/utils/vendor.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/components/grid-items.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2024 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Box, Grid, type GridProps } from '@mui/material'\nimport { forwardRef } from 'react'\n\n/* eslint-disable-next-line */\nexport interface GridItemsProps\n extends GridProps,\n ReplaceKey<JSX.OverrideableComponentProps, 'component', 'itemComponent'> {\n items: GridProps[]\n /**\n * Lay the items out as MASONRY instead of rigid rows.\n *\n * ## The bug this exists to kill\n *\n * A `<GridItems>` of cards is a twelve-column flex row that wraps, and every\n * item in a wrapped row is as tall as the tallest one in it. Two consequences,\n * both reported from real pages:\n *\n * 1. **Holes.** Billing puts `Current plan` (4) beside `Usage` (8). `Usage` is\n * more than twice as tall, so the row is `Usage`-tall and the area under\n * `Current plan` is dead — while `Metered usage estimate` (4), the card\n * shaped to fill it, is pushed onto its own row far below with eight\n * columns of nothing beside it.\n * 2. **The stranded sidebar.** The marketplace listing detail is `body` (8),\n * `changelog` (8), `sidebar` (4). Two eights cannot share a row, so the\n * changelog wraps — and the sidebar, which follows it in source order,\n * wraps WITH it. `Install`, the point of the page, starts a screen below\n * the top of the content with blank space above it.\n *\n * ## What it does instead\n *\n * Items are bucketed into COLUMNS by their `size`, and each column stacks its\n * own cards at their natural heights. `Current plan` and `Metered usage\n * estimate` are both 4-wide, so they become one 4-wide column beside the\n * 8-wide `Usage` column; `body` and `changelog` become one 8-wide column\n * beside the 4-wide sidebar. A full-width item (span 12) interrupts the\n * bucketing and takes a band of its own, so source order is preserved across\n * it — without that, billing's five full-width cards would collect at the\n * bottom in one column and reorder the page.\n *\n * ## Why bucketing rather than measured row spans\n *\n * The obvious implementation is a fine-grained row grid where each card's\n * MEASURED height becomes a `grid-row: span n`, packed `dense`. It was built\n * that way first and it is a trap: `n` is only correct until the card's\n * content changes size, and a card whose `n` is too small does not merely\n * leave a gap — the next card is placed UNDERNEATH IT. Overlapping cards are\n * a far worse defect than the holes this mode exists to close, and they\n * appear exactly when measurement is least reliable (data still arriving,\n * images still decoding). Keeping the whole thing in CSS means there is no\n * measurement to go stale: heights are whatever the browser computes, every\n * frame, and cards cannot overlap because nothing ever claims a height on\n * their behalf.\n *\n * It also costs nothing at hydration. A measured layout renders wrong on the\n * server and corrects on mount; this renders identically in both.\n *\n * ## The one behaviour change\n *\n * At a breakpoint where every item is full width (`xs: 12`, the phone case)\n * the columns stack, so cards are read column by column rather than in the\n * authored order — on billing, `Current plan` then `Metered usage estimate`\n * then `Usage`. Cards that share a column are the ones that share a width,\n * which in practice is what makes them belong together.\n */\n masonry?: boolean\n}\n\n/**\n * Cards of unequal height are the common case, and a row is as tall as its\n * tallest card, so the default leaves no hole for a short card to sit in.\n * Pass `masonry={false}` where the items really are a ROW — tiles, buttons, a\n * navigation column beside its content, a band of stat figures — and say so\n * where you pass it, because a row is now the deliberate choice.\n */\nconst MASONRY_BY_DEFAULT = true\n\n/** A per-breakpoint column count, normalized from MUI's `size`. */\ntype SpanProfile = Record<string, number>\n\n/** The breakpoint an item with no explicit `size` is sized at. */\nconst BASE_BREAKPOINT = 'xs'\nconst FULL_SPAN = 12\n\n/**\n * MUI Grid props that describe the flex-row layout masonry replaces, and so\n * must not reach the masonry container.\n */\nconst FLEX_ROW_PROPS = [\n 'container',\n 'spacing',\n 'rowSpacing',\n 'columnSpacing',\n 'columns',\n 'direction',\n 'wrap',\n 'size',\n 'offset',\n] as const\n\n/**\n * An item's `size` as a per-breakpoint column count.\n *\n * `'auto'`/`'grow'` have no column-count equivalent and become full width,\n * which is the safe reading: an item that wanted to size itself gets a band of\n * its own rather than being bucketed against a width it never declared.\n */\nfunction spanProfile(size: GridProps['size']): SpanProfile {\n const one = (value: unknown) =>\n typeof value === 'number' && value > 0 ? Math.min(FULL_SPAN, Math.round(value)) : FULL_SPAN\n if (size == null) return { [BASE_BREAKPOINT]: FULL_SPAN }\n if (typeof size === 'number' || typeof size === 'string')\n return { [BASE_BREAKPOINT]: one(size) }\n if (Array.isArray(size)) return { [BASE_BREAKPOINT]: one(size[0]) }\n const entries = Object.entries(size).map(\n ([breakpoint, value]) => [breakpoint, one(value)] as const,\n )\n return entries.length ? Object.fromEntries(entries) : { [BASE_BREAKPOINT]: FULL_SPAN }\n}\n\n/** The profile as a `grid-column` value `sx` can resolve per breakpoint. */\nconst gridColumnFor = (profile: SpanProfile) =>\n Object.fromEntries(\n Object.entries(profile).map(([breakpoint, span]) => [breakpoint, `span ${span}`]),\n )\n\n/** MUI's breakpoint keys, narrowest first. */\nconst BREAKPOINT_ORDER = ['xs', 'sm', 'md', 'lg', 'xl'] as const\n\n/**\n * The column count at the WIDEST breakpoint the item declares — the width it is\n * bucketed by.\n *\n * Not `Math.max` over the profile, which was the first attempt and is wrong in\n * a way that silently disables the whole mode: essentially every item in this\n * codebase is written `{ xs: 12, md: 4 }`, so the maximum is 12 for all of them\n * and every card reads as full width. It has to be the value at the widest\n * declared breakpoint — 4 — because the multi-column arrangement only exists at\n * wide viewports in the first place.\n *\n * Read from the profile rather than from the current viewport on purpose:\n * measuring the breakpoint in JS would make the server and client renders\n * disagree. Bucketing is decided once; `sx` resolves the responsive\n * `grid-column` in CSS, so the narrow layout still collapses to a stack.\n */\nconst layoutSpan = (profile: SpanProfile) => {\n const declared = BREAKPOINT_ORDER.filter((breakpoint) => profile[breakpoint] != null)\n const widest = declared[declared.length - 1]\n return widest ? profile[widest] : FULL_SPAN\n}\n\n/** `sx` (which may already be an array or a function) as a flat array. */\nconst sxArray = (sx: unknown): any[] => (sx == null ? [] : Array.isArray(sx) ? sx : [sx])\n\ninterface MasonryColumn {\n key: string\n profile: SpanProfile\n entries: Array<{ item: GridProps; index: number }>\n}\n\n/**\n * A band of ONE width fans out; a band of mixed widths does not.\n *\n * Same-size items sharing a column is right when something else occupies the\n * rest of the row — billing's two 4-wide cards stacked beside its 8-wide\n * `Usage` is the case this mode was built for. It is wrong when the band is\n * ALL of that width: eight `md: 6` health probes then queue in one 6-wide\n * column with six columns of nothing beside them, which is a worse layout than\n * the rigid rows masonry replaced.\n *\n * So a single-width band spreads across the `12 / span` columns it was asking\n * for, round-robin, which keeps left-to-right reading order — item 0 top-left,\n * item 1 top-right — rather than the column-major order that filling one\n * column at a time would give.\n */\nfunction fanOut(band: MasonryColumn[]): MasonryColumn[] {\n if (band.length !== 1) return band\n const [column] = band\n const span = layoutSpan(column.profile)\n const columns = Math.floor(FULL_SPAN / span)\n if (columns < 2 || column.entries.length < 2) return band\n const spread: MasonryColumn[] = Array.from({ length: columns }, (_, i) => ({\n key: `${column.key}#${i}`,\n profile: column.profile,\n // Typed, not inferred: an empty literal is `any[]` under the stricter\n // library tsconfigs even though the annotation above it is not enough to\n // narrow a property inside `Array.from`'s callback.\n entries: [] as MasonryColumn['entries'],\n }))\n column.entries.forEach((entry, index) => {\n spread[index % columns].entries.push(entry)\n })\n return spread.filter((candidate) => candidate.entries.length > 0)\n}\n\n/**\n * Marks an element as a frame around content that others draw, such as the\n * console's widget zone stacking the cards plugins render (AGL-3050).\n *\n * `GridItems masonry` and `CardColumns` hide an item that rendered nothing.\n * An item holding only a frame whose contents all drew nothing is the same\n * absent card one level down, and the item is not `:empty` while the frame is\n * in it, so both hide that item too. The mark is what tells a frame apart\n * from an element that draws something with no children of its own: an item\n * whose one element is an image, a divider or a loading skeleton is never\n * mistaken for an absent card.\n */\nexport const ABSENT_WHEN_EMPTY_ATTRIBUTE = 'data-absent-when-empty'\n\n/** The mark, as props to spread onto the frame: `<Stack {...ABSENT_WHEN_EMPTY}>`. */\nexport const ABSENT_WHEN_EMPTY = { [ABSENT_WHEN_EMPTY_ATTRIBUTE]: '' } as const\n\n/**\n * A marked frame that is its parent's only element and drew nothing.\n *\n * Attribute last: the selector engine jsdom ships misreads an attribute\n * selector that opens a compound inside `:has()`, and throws.\n */\nexport const EMPTY_FRAME_SELECTOR = `:only-child:empty[${ABSENT_WHEN_EMPTY_ATTRIBUTE}]`\n\n/**\n * A column with nothing to draw, hidden wherever it spans the whole row.\n *\n * Hiding its item is not enough. The column is a grid item of its own, so a\n * column whose item is hidden would stay behind as a zero-height grid row with\n * the grid's `gap` on both sides of it: a double gap between the cards around\n * an absent full-width band. A full-width item is always the only item in its\n * column, and it is absent in two shapes: it rendered nothing, or it holds\n * only a frame that drew nothing.\n *\n * Only at the widths where the column spans all twelve tracks. A narrower\n * column shares its row with the columns beside it, so an empty one adds no\n * row there, and hiding it would let auto-placement slide the next column into\n * its tracks.\n */\nfunction emptyColumnRules(profile: SpanProfile) {\n const display = Object.fromEntries(\n Object.entries(profile).map(([breakpoint, span]) => [\n breakpoint,\n span >= FULL_SPAN ? 'none' : 'flex',\n ]),\n )\n return {\n '&:has(> :only-child:empty)': { display },\n [`&:has(> :only-child > ${EMPTY_FRAME_SELECTOR})`]: { display },\n }\n}\n\n/**\n * Items → bands → columns.\n *\n * A band is a maximal run of items that are not full width; a full-width item\n * is a band on its own. Within a band, items that declare the same `size` share\n * a column, in source order — unless the band is entirely one width, which\n * {@link fanOut} spreads.\n */\nfunction buildBands(items: GridProps[]): MasonryColumn[][] {\n const bands: MasonryColumn[][] = []\n let current: MasonryColumn[] | null = null\n\n items.forEach((item, index) => {\n const profile = spanProfile(item.size)\n const key = JSON.stringify(profile)\n if (layoutSpan(profile) >= FULL_SPAN) {\n bands.push([{ key, profile, entries: [{ item, index }] }])\n current = null\n return\n }\n if (!current) {\n current = []\n bands.push(current)\n }\n const column = current.find((candidate) => candidate.key === key)\n if (column) column.entries.push({ item, index })\n else current.push({ key, profile, entries: [{ item, index }] })\n })\n\n return bands.map(fanOut)\n}\n\nexport const GridItems = forwardRef<any, GridItemsProps>((props, ref) => {\n const {\n items = [],\n itemComponent: ItemComponent = Grid,\n masonry = MASONRY_BY_DEFAULT,\n spacing = 0,\n sx,\n ...rest\n } = props\n\n if (!masonry) {\n return (\n <Grid ref={ref} container spacing={spacing} sx={sx as any} {...rest}>\n {items.map(\n ({ key: itemKey, id, ...item }: GridProps & { id?: unknown }, index: number) => (\n <ItemComponent key={itemKey ?? id ?? index} {...item} />\n ),\n )}\n </Grid>\n )\n }\n\n const gap = spacing\n const containerProps = Object.fromEntries(\n Object.entries(rest).filter(([key]) => !FLEX_ROW_PROPS.includes(key as any)),\n )\n\n return (\n <Box\n ref={ref}\n {...(containerProps as any)}\n sx={[\n {\n display: 'grid',\n // Twelve fractional tracks with a zero minimum. A `span` can never\n // resolve wider than its share of the container, and `minmax(0, 1fr)`\n // stops a wide child (a table, a long unbroken string) from pushing a\n // track past the edge — which is what used to shove the listing\n // page's sidebar out of the viewport.\n gridTemplateColumns: `repeat(${FULL_SPAN}, minmax(0, 1fr))`,\n // Columns are as tall as their own contents, never as tall as the\n // tallest column beside them.\n alignItems: 'start',\n gap,\n },\n ...sxArray(sx),\n ]}\n >\n {buildBands(items).map((band, bandIndex) =>\n band.map((column) => (\n <Box\n key={`${bandIndex}:${column.key}`}\n sx={{\n gridColumn: gridColumnFor(column.profile),\n display: 'flex',\n flexDirection: 'column',\n gap,\n // Without this a flex column refuses to shrink below its content's\n // intrinsic width and the grid track overflows with it.\n minWidth: 0,\n // An item whose children rendered NOTHING must not leave a gap.\n // A plugin widget slot renders nothing when no plugin is\n // entitled for it, and the wrapper it leaves behind is still a\n // flex child — so the column's `gap` is applied on both sides of\n // a zero-height box, drawing a hole exactly where the absent card\n // was. `:empty` is exact: the wrapper has no element and no text\n // node in that case and only in that case.\n '& > *:empty': { display: 'none' },\n // The same absent card one level down: the item's one element is\n // a marked frame whose contents all drew nothing.\n [`& > *:has(> ${EMPTY_FRAME_SELECTOR})`]: { display: 'none' },\n ...emptyColumnRules(column.profile),\n }}\n >\n {column.entries.map(({ item, index }) => {\n const { key: itemKey, id, size, sx: itemSx, ...itemRest } = item as GridProps & {\n id?: unknown\n }\n return (\n <ItemComponent\n key={itemKey ?? id ?? index}\n {...itemRest}\n sx={[{ minWidth: 0 }, ...sxArray(itemSx)]}\n />\n )\n })}\n </Box>\n )),\n )}\n </Box>\n )\n})\n\nGridItems.displayName = 'GridItems'\nGridItems.aglyn = true\n\nexport default GridItems\n"],"names":["Box","Grid","forwardRef","MASONRY_BY_DEFAULT","BASE_BREAKPOINT","FULL_SPAN","FLEX_ROW_PROPS","spanProfile","size","one","value","Math","min","round","Array","isArray","entries","Object","map","breakpoint","length","fromEntries","gridColumnFor","profile","span","BREAKPOINT_ORDER","layoutSpan","declared","filter","widest","sxArray","sx","fanOut","band","column","columns","floor","spread","from","_","i","key","forEach","entry","index","push","candidate","ABSENT_WHEN_EMPTY_ATTRIBUTE","ABSENT_WHEN_EMPTY","EMPTY_FRAME_SELECTOR","emptyColumnRules","display","buildBands","items","bands","current","item","JSON","stringify","find","GridItems","props","ref","itemComponent","ItemComponent","masonry","spacing","rest","container","itemKey","id","gap","containerProps","includes","gridTemplateColumns","alignItems","bandIndex","gridColumn","flexDirection","minWidth","itemSx","itemRest","displayName","aglyn"],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type SxProps } from '@aglyn/shared-ui-theme';
|
|
18
|
+
import { type GridProps as MuiGridProps } from '@mui/material';
|
|
19
|
+
import { type VirtuosoGridHandle, type VirtuosoGridProps } from 'react-virtuoso';
|
|
20
|
+
import { type ContainerProps } from './container';
|
|
21
|
+
export type VirtualizedGridProps = VirtuosoGridProps<any> & {
|
|
22
|
+
sx?: SxProps;
|
|
23
|
+
as?: any;
|
|
24
|
+
};
|
|
25
|
+
export type GridListItemData<P = any> = {
|
|
26
|
+
id: MapKey;
|
|
27
|
+
} & P;
|
|
28
|
+
export interface GridListProps extends Partial<VirtualizedGridProps> {
|
|
29
|
+
items?: GridListItemData[];
|
|
30
|
+
renderItemContent?: (item: GridListProps['items'][number], index: number, items: GridListProps['items']) => JSX.Node;
|
|
31
|
+
GridContainerProps?: MuiGridProps;
|
|
32
|
+
GridItemProps?: MuiGridProps;
|
|
33
|
+
ListWrapperProps?: ContainerProps;
|
|
34
|
+
sx?: SxProps;
|
|
35
|
+
}
|
|
36
|
+
export declare const GridList: import("react").ForwardRefExoticComponent<GridListProps & import("react").RefAttributes<VirtuosoGridHandle>>;
|
|
37
|
+
export default GridList;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
/**
|
|
5
|
+
* @license
|
|
6
|
+
* Copyright 2023 Aglyn LLC
|
|
7
|
+
*
|
|
8
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
9
|
+
* you may not use this file except in compliance with the License.
|
|
10
|
+
* You may obtain a copy of the License at
|
|
11
|
+
*
|
|
12
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
+
*
|
|
14
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
+
* See the License for the specific language governing permissions and
|
|
18
|
+
* limitations under the License.
|
|
19
|
+
*/ import { generateComponentClassKeys, mergeSxProps, styled } from "@aglyn/shared-ui-theme";
|
|
20
|
+
import { Box, Card, Grid } from "@mui/material";
|
|
21
|
+
import clsx from "clsx";
|
|
22
|
+
import { forwardRef, useCallback, useMemo } from "react";
|
|
23
|
+
import { VirtuosoGrid } from "react-virtuoso";
|
|
24
|
+
import Container from "./container.js";
|
|
25
|
+
const classKey = generateComponentClassKeys('AglynGridList', [
|
|
26
|
+
'itemWrapper',
|
|
27
|
+
'itemContent',
|
|
28
|
+
'gridContainer',
|
|
29
|
+
'gridItem'
|
|
30
|
+
]);
|
|
31
|
+
const ItemWrapper = styled(/*#__PURE__*/ forwardRef((props, ref)=>{
|
|
32
|
+
const { children, className, sx } = props, rest = _object_without_properties_loose(props, [
|
|
33
|
+
"children",
|
|
34
|
+
"className",
|
|
35
|
+
"sx"
|
|
36
|
+
]);
|
|
37
|
+
return /*#__PURE__*/ _jsx(Box, _extends({
|
|
38
|
+
ref: ref,
|
|
39
|
+
className: clsx(classKey.itemWrapper, className),
|
|
40
|
+
sx: mergeSxProps({
|
|
41
|
+
height: 0,
|
|
42
|
+
position: 'relative',
|
|
43
|
+
paddingTop: `${3 / 4 * 100}%`
|
|
44
|
+
}, sx)
|
|
45
|
+
}, rest, {
|
|
46
|
+
children: /*#__PURE__*/ _jsx(Card, {
|
|
47
|
+
className: classKey.itemContent,
|
|
48
|
+
sx: {
|
|
49
|
+
position: 'absolute',
|
|
50
|
+
left: 0,
|
|
51
|
+
top: 0,
|
|
52
|
+
width: '100%',
|
|
53
|
+
height: '100%',
|
|
54
|
+
display: 'flex',
|
|
55
|
+
textAlign: 'center',
|
|
56
|
+
flexDirection: 'column',
|
|
57
|
+
justifyContent: 'space-evenly'
|
|
58
|
+
},
|
|
59
|
+
children: children
|
|
60
|
+
})
|
|
61
|
+
}));
|
|
62
|
+
}), {
|
|
63
|
+
name: 'AglynItemWrapper'
|
|
64
|
+
})({});
|
|
65
|
+
const VirtualizedGrid = styled(VirtuosoGrid, {
|
|
66
|
+
name: 'AglynVirtualizedGrid'
|
|
67
|
+
})({});
|
|
68
|
+
export const GridList = /*#__PURE__*/ forwardRef(function RefRenderFn(props, ref) {
|
|
69
|
+
const { items = [], renderItemContent = (item)=>item, ListWrapperProps = {}, GridContainerProps = {}, GridItemProps = {}, components } = props, rest = _object_without_properties_loose(props, [
|
|
70
|
+
"items",
|
|
71
|
+
"renderItemContent",
|
|
72
|
+
"ListWrapperProps",
|
|
73
|
+
"GridContainerProps",
|
|
74
|
+
"GridItemProps",
|
|
75
|
+
"components"
|
|
76
|
+
]);
|
|
77
|
+
const computeItemKey = useCallback((index)=>{
|
|
78
|
+
var _ref, _ref1;
|
|
79
|
+
const item = items[index];
|
|
80
|
+
return (_ref = (_ref1 = item == null ? void 0 : item.key) != null ? _ref1 : item == null ? void 0 : item.id) != null ? _ref : items.indexOf(item);
|
|
81
|
+
}, [
|
|
82
|
+
items
|
|
83
|
+
]);
|
|
84
|
+
const GridContainer = useMemo(()=>/*#__PURE__*/ forwardRef(function RefRenderFn(_0, _1) {
|
|
85
|
+
let _ref = [
|
|
86
|
+
_0,
|
|
87
|
+
_1
|
|
88
|
+
], [_ref1, ..._rest] = _ref, { className } = _ref1, props = _object_without_properties_loose(_ref1, [
|
|
89
|
+
"className"
|
|
90
|
+
]), [ref] = _rest;
|
|
91
|
+
const { className: gridClassName, children } = GridContainerProps, restGridProps = _object_without_properties_loose(GridContainerProps, [
|
|
92
|
+
"className",
|
|
93
|
+
"children"
|
|
94
|
+
]);
|
|
95
|
+
return /*#__PURE__*/ _jsxs(Container, _extends({
|
|
96
|
+
gutterY: true
|
|
97
|
+
}, ListWrapperProps, {
|
|
98
|
+
children: [
|
|
99
|
+
children,
|
|
100
|
+
/*#__PURE__*/ _jsx(Grid, _extends({
|
|
101
|
+
ref: ref,
|
|
102
|
+
className: clsx(classKey.gridContainer, gridClassName, className),
|
|
103
|
+
container: true
|
|
104
|
+
}, restGridProps, props))
|
|
105
|
+
]
|
|
106
|
+
}));
|
|
107
|
+
}), [
|
|
108
|
+
ListWrapperProps,
|
|
109
|
+
GridContainerProps
|
|
110
|
+
]);
|
|
111
|
+
const GridItem = useMemo(()=>{
|
|
112
|
+
const Component = /*#__PURE__*/ forwardRef(function RefRenderFn(itemProps, ref) {
|
|
113
|
+
const { className: gridClassName } = GridItemProps, restGridProps = _object_without_properties_loose(GridItemProps, [
|
|
114
|
+
"className"
|
|
115
|
+
]);
|
|
116
|
+
const { className } = itemProps, rest = _object_without_properties_loose(itemProps, [
|
|
117
|
+
"className"
|
|
118
|
+
]);
|
|
119
|
+
// `rest` carries Virtuoso's per-item props INCLUDING `children`
|
|
120
|
+
// (the rendered item) — dropping it rendered every cell empty
|
|
121
|
+
// (AGL-459: blank icon picker).
|
|
122
|
+
return /*#__PURE__*/ _jsx(Grid, _extends({
|
|
123
|
+
ref: ref,
|
|
124
|
+
className: clsx(classKey.gridItem, gridClassName, className)
|
|
125
|
+
}, restGridProps, rest));
|
|
126
|
+
});
|
|
127
|
+
Component.displayName = 'GridListItem';
|
|
128
|
+
Component.aglyn = true;
|
|
129
|
+
return Component;
|
|
130
|
+
}, [
|
|
131
|
+
GridItemProps
|
|
132
|
+
]);
|
|
133
|
+
const handleItemContent = useCallback((index)=>{
|
|
134
|
+
return /*#__PURE__*/ _jsx(ItemWrapper, {
|
|
135
|
+
children: renderItemContent(items[index], index, items)
|
|
136
|
+
});
|
|
137
|
+
}, [
|
|
138
|
+
items,
|
|
139
|
+
renderItemContent
|
|
140
|
+
]);
|
|
141
|
+
return /*#__PURE__*/ _jsx(VirtualizedGrid, _extends({
|
|
142
|
+
ref: ref,
|
|
143
|
+
computeItemKey: computeItemKey,
|
|
144
|
+
itemContent: handleItemContent,
|
|
145
|
+
totalCount: items.length,
|
|
146
|
+
components: _extends({
|
|
147
|
+
Item: GridItem,
|
|
148
|
+
List: GridContainer
|
|
149
|
+
}, components)
|
|
150
|
+
}, rest));
|
|
151
|
+
});
|
|
152
|
+
GridList.displayName = 'GridList';
|
|
153
|
+
GridList.aglyn = true;
|
|
154
|
+
export default GridList;
|
|
155
|
+
|
|
156
|
+
//# sourceMappingURL=grid-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/components/grid-list.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2023 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n generateComponentClassKeys,\n mergeSxProps,\n styled,\n type SxProps,\n} from '@aglyn/shared-ui-theme'\nimport {\n Box,\n type BoxProps,\n Card,\n Grid,\n type GridProps as MuiGridProps,\n} from '@mui/material'\nimport clsx from 'clsx'\nimport { forwardRef, useCallback, useMemo } from 'react'\nimport {\n VirtuosoGrid,\n type VirtuosoGridHandle,\n type VirtuosoGridProps,\n} from 'react-virtuoso'\nimport Container, { type ContainerProps } from './container'\n\nconst classKey = generateComponentClassKeys('AglynGridList', [\n 'itemWrapper',\n 'itemContent',\n 'gridContainer',\n 'gridItem',\n])\n\nconst ItemWrapper = styled(\n forwardRef<any, BoxProps>((props, ref) => {\n const { children, className, sx, ...rest } = props\n return (\n <Box\n ref={ref}\n className={clsx(classKey.itemWrapper, className)}\n sx={mergeSxProps(\n {\n height: 0,\n position: 'relative',\n paddingTop: `${(3 / 4) * 100}%`, // 4:3\n },\n sx,\n )}\n {...rest}\n >\n <Card\n className={classKey.itemContent}\n sx={{\n position: 'absolute',\n left: 0,\n top: 0,\n width: '100%',\n height: '100%',\n display: 'flex',\n textAlign: 'center',\n flexDirection: 'column',\n justifyContent: 'space-evenly',\n }}\n >\n {children}\n </Card>\n </Box>\n )\n }),\n {\n name: 'AglynItemWrapper',\n },\n)({})\n\nexport type VirtualizedGridProps = VirtuosoGridProps<any> & {\n sx?: SxProps\n as?: any\n}\nconst VirtualizedGrid = styled(VirtuosoGrid, {\n name: 'AglynVirtualizedGrid',\n})<VirtualizedGridProps>({})\n\nexport type GridListItemData<P = any> = { id: MapKey } & P\n\n/* eslint-disable-next-line */\nexport interface GridListProps extends Partial<VirtualizedGridProps> {\n items?: GridListItemData[]\n renderItemContent?: (\n item: GridListProps['items'][number],\n index: number,\n items: GridListProps['items'],\n ) => JSX.Node\n GridContainerProps?: MuiGridProps\n GridItemProps?: MuiGridProps\n ListWrapperProps?: ContainerProps\n sx?: SxProps\n}\n\nexport const GridList = forwardRef<VirtuosoGridHandle, GridListProps>(\n function RefRenderFn(props, ref) {\n const {\n items = [],\n renderItemContent = (item) => item,\n ListWrapperProps = {},\n GridContainerProps = {},\n GridItemProps = {},\n components,\n ...rest\n } = props\n\n const computeItemKey = useCallback(\n (index: number) => {\n const item = items[index]\n return item?.key ?? item?.id ?? items.indexOf(item)\n },\n [items],\n )\n\n const GridContainer = useMemo(\n () =>\n forwardRef<any, MuiGridProps>(function RefRenderFn(\n { className, ...props },\n ref,\n ) {\n const {\n className: gridClassName,\n children,\n ...restGridProps\n } = GridContainerProps\n return (\n <Container gutterY {...ListWrapperProps}>\n {children}\n <Grid\n ref={ref}\n className={clsx(\n classKey.gridContainer,\n gridClassName,\n className,\n )}\n container\n {...restGridProps}\n {...props}\n />\n </Container>\n )\n }),\n [ListWrapperProps, GridContainerProps],\n )\n\n const GridItem = useMemo(() => {\n const Component = forwardRef<any, MuiGridProps>(\n function RefRenderFn(itemProps, ref) {\n const { className: gridClassName, ...restGridProps } = GridItemProps\n const { className, ...rest } = itemProps\n // `rest` carries Virtuoso's per-item props INCLUDING `children`\n // (the rendered item) — dropping it rendered every cell empty\n // (AGL-459: blank icon picker).\n return (\n <Grid\n ref={ref}\n className={clsx(classKey.gridItem, gridClassName, className)}\n {...restGridProps}\n {...rest}\n />\n )\n },\n )\n Component.displayName = 'GridListItem'\n Component.aglyn = true\n return Component\n }, [GridItemProps])\n\n const handleItemContent = useCallback(\n (index: number) => {\n return (\n <ItemWrapper>\n {renderItemContent(items[index], index, items)}\n </ItemWrapper>\n )\n },\n [items, renderItemContent],\n )\n\n return (\n <VirtualizedGrid\n ref={ref}\n computeItemKey={computeItemKey}\n itemContent={handleItemContent}\n totalCount={items.length}\n components={{\n Item: GridItem,\n List: GridContainer,\n ...components,\n }}\n {...rest}\n />\n )\n },\n)\n\nGridList.displayName = 'GridList'\nGridList.aglyn = true\n\nexport default GridList\n"],"names":["generateComponentClassKeys","mergeSxProps","styled","Box","Card","Grid","clsx","forwardRef","useCallback","useMemo","VirtuosoGrid","Container","classKey","ItemWrapper","props","ref","children","className","sx","rest","itemWrapper","height","position","paddingTop","itemContent","left","top","width","display","textAlign","flexDirection","justifyContent","name","VirtualizedGrid","GridList","RefRenderFn","items","renderItemContent","item","ListWrapperProps","GridContainerProps","GridItemProps","components","computeItemKey","index","key","id","indexOf","GridContainer","gridClassName","restGridProps","gutterY","gridContainer","container","GridItem","Component","itemProps","gridItem","displayName","aglyn","handleItemContent","totalCount","length","Item","List"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type SxProps } from '@mui/material';
|
|
2
|
+
import type { MouseEventHandler, ReactNode } from 'react';
|
|
3
|
+
/** Content shape accepted anywhere a help affordance can attach (AGL-600/601). */
|
|
4
|
+
export interface HelpTipContent {
|
|
5
|
+
/** One- or two-sentence plain-language explanation shown in the tooltip. */
|
|
6
|
+
excerpt: ReactNode;
|
|
7
|
+
/** Optional bold first line, usually the matching docs page/section title. */
|
|
8
|
+
title?: ReactNode;
|
|
9
|
+
/** Optional documentation deep link; opens in a new tab. */
|
|
10
|
+
href?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface HelpTipProps extends HelpTipContent {
|
|
13
|
+
/** Accessible name for the affordance; defaults from the title. */
|
|
14
|
+
ariaLabel?: string;
|
|
15
|
+
sx?: SxProps;
|
|
16
|
+
/** Forwarded to the icon button — e.g. to stop propagation when the tip
|
|
17
|
+
* sits inside a clickable parent like an accordion summary. */
|
|
18
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Unobtrusive question-mark help affordance: hover for a brief explanation,
|
|
22
|
+
* click (when `href` is set) to open the documentation page in a new tab.
|
|
23
|
+
* The shared primitive behind the console's docs help system (AGL-599..601).
|
|
24
|
+
*/
|
|
25
|
+
export declare function HelpTip(props: HelpTipProps): import("react").JSX.Element;
|
|
26
|
+
export declare namespace HelpTip {
|
|
27
|
+
var displayName: string;
|
|
28
|
+
var aglyn: boolean;
|
|
29
|
+
}
|
|
30
|
+
export default HelpTip;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { mdiHelpCircleOutline, mdiOpenInNew } from "@aglyn/shared-data-mdi";
|
|
19
|
+
import { mergeSxProps } from "@aglyn/shared-ui-theme";
|
|
20
|
+
import { IconButton, Link, Stack, Tooltip, Typography } from "@mui/material";
|
|
21
|
+
import { useCallback, useRef } from "react";
|
|
22
|
+
import { MdiIcon } from "./mdi-icon/mdi-icon.js";
|
|
23
|
+
/**
|
|
24
|
+
* Unobtrusive question-mark help affordance: hover for a brief explanation,
|
|
25
|
+
* click (when `href` is set) to open the documentation page in a new tab.
|
|
26
|
+
* The shared primitive behind the console's docs help system (AGL-599..601).
|
|
27
|
+
*/ export function HelpTip(props) {
|
|
28
|
+
const { excerpt, title, href, ariaLabel, sx, onClick } = props;
|
|
29
|
+
const label = ariaLabel != null ? ariaLabel : typeof title === 'string' ? `Help: ${title}` : 'Help';
|
|
30
|
+
// Popper places the tooltip when it opens, and recomputes only on scroll, on
|
|
31
|
+
// a window resize, or when the popper component itself re-renders. The
|
|
32
|
+
// content can still grow after that — a console excerpt is a chunk fetched
|
|
33
|
+
// on first open (AGL-2706) — and a tip placed at its title-only width then
|
|
34
|
+
// widens from where it was put, off the screen at the right edge (AGL-2855).
|
|
35
|
+
// So the open content reports its own size changes to the popper.
|
|
36
|
+
const popper = useRef(null);
|
|
37
|
+
const setPopper = useCallback((instance)=>{
|
|
38
|
+
popper.current = instance;
|
|
39
|
+
}, []);
|
|
40
|
+
const contentObserver = useRef(null);
|
|
41
|
+
const observeContent = useCallback((node)=>{
|
|
42
|
+
var _contentObserver_current;
|
|
43
|
+
(_contentObserver_current = contentObserver.current) == null ? void 0 : _contentObserver_current.disconnect();
|
|
44
|
+
contentObserver.current = null;
|
|
45
|
+
// No ResizeObserver means no layout to follow (jsdom).
|
|
46
|
+
if (!node || typeof ResizeObserver === 'undefined') return;
|
|
47
|
+
contentObserver.current = new ResizeObserver(()=>{
|
|
48
|
+
var _popper_current;
|
|
49
|
+
void ((_popper_current = popper.current) == null ? void 0 : _popper_current.update());
|
|
50
|
+
});
|
|
51
|
+
contentObserver.current.observe(node);
|
|
52
|
+
}, []);
|
|
53
|
+
const content = /*#__PURE__*/ _jsxs(Stack, {
|
|
54
|
+
ref: observeContent,
|
|
55
|
+
spacing: 0.5,
|
|
56
|
+
sx: {
|
|
57
|
+
p: 0.5,
|
|
58
|
+
maxWidth: 280
|
|
59
|
+
},
|
|
60
|
+
children: [
|
|
61
|
+
title ? /*#__PURE__*/ _jsx(Typography, {
|
|
62
|
+
variant: "subtitle2",
|
|
63
|
+
component: "span",
|
|
64
|
+
children: title
|
|
65
|
+
}) : null,
|
|
66
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
67
|
+
variant: "caption",
|
|
68
|
+
component: "span",
|
|
69
|
+
children: excerpt
|
|
70
|
+
}),
|
|
71
|
+
href ? /*#__PURE__*/ _jsxs(Link, {
|
|
72
|
+
href: href,
|
|
73
|
+
target: "_blank",
|
|
74
|
+
rel: "noopener noreferrer",
|
|
75
|
+
variant: "caption",
|
|
76
|
+
sx: {
|
|
77
|
+
display: 'inline-flex',
|
|
78
|
+
alignItems: 'center',
|
|
79
|
+
gap: 0.5,
|
|
80
|
+
color: 'inherit',
|
|
81
|
+
fontWeight: 600
|
|
82
|
+
},
|
|
83
|
+
children: [
|
|
84
|
+
"Open documentation",
|
|
85
|
+
/*#__PURE__*/ _jsx(MdiIcon, {
|
|
86
|
+
path: mdiOpenInNew.path,
|
|
87
|
+
sx: {
|
|
88
|
+
fontSize: '1em'
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
}) : null
|
|
93
|
+
]
|
|
94
|
+
});
|
|
95
|
+
const iconSx = mergeSxProps({
|
|
96
|
+
color: 'text.disabled',
|
|
97
|
+
':hover': {
|
|
98
|
+
color: 'text.secondary'
|
|
99
|
+
}
|
|
100
|
+
}, sx);
|
|
101
|
+
return /*#__PURE__*/ _jsx(Tooltip, {
|
|
102
|
+
arrow: true,
|
|
103
|
+
enterDelay: 150,
|
|
104
|
+
title: content,
|
|
105
|
+
slotProps: {
|
|
106
|
+
popper: {
|
|
107
|
+
popperRef: setPopper
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
children: href ? /*#__PURE__*/ _jsx(IconButton, {
|
|
111
|
+
component: "a",
|
|
112
|
+
href: href,
|
|
113
|
+
target: "_blank",
|
|
114
|
+
rel: "noopener noreferrer",
|
|
115
|
+
size: "small",
|
|
116
|
+
"aria-label": `${label} — open documentation in a new tab`,
|
|
117
|
+
sx: iconSx,
|
|
118
|
+
onClick: onClick,
|
|
119
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
120
|
+
path: mdiHelpCircleOutline.path,
|
|
121
|
+
fontSize: "inherit"
|
|
122
|
+
})
|
|
123
|
+
}) : /*#__PURE__*/ _jsx(IconButton, {
|
|
124
|
+
size: "small",
|
|
125
|
+
"aria-label": label,
|
|
126
|
+
sx: iconSx,
|
|
127
|
+
onClick: onClick,
|
|
128
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
129
|
+
path: mdiHelpCircleOutline.path,
|
|
130
|
+
fontSize: "inherit"
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
HelpTip.displayName = 'HelpTip';
|
|
136
|
+
HelpTip.aglyn = true;
|
|
137
|
+
export default HelpTip;
|
|
138
|
+
|
|
139
|
+
//# sourceMappingURL=help-tip.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/components/help-tip.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { mdiHelpCircleOutline, mdiOpenInNew } from '@aglyn/shared-data-mdi'\nimport { mergeSxProps } from '@aglyn/shared-ui-theme'\nimport {\n IconButton,\n Link,\n Stack,\n type SxProps,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { useCallback, useRef } from 'react'\nimport type { MouseEventHandler, ReactNode } from 'react'\nimport { MdiIcon } from './mdi-icon/mdi-icon'\n\n/** The one part of a Popper.js instance a help tip calls. */\ninterface PlacedPopper {\n update(): unknown\n}\n\n/** Content shape accepted anywhere a help affordance can attach (AGL-600/601). */\nexport interface HelpTipContent {\n /** One- or two-sentence plain-language explanation shown in the tooltip. */\n excerpt: ReactNode\n /** Optional bold first line, usually the matching docs page/section title. */\n title?: ReactNode\n /** Optional documentation deep link; opens in a new tab. */\n href?: string\n}\n\nexport interface HelpTipProps extends HelpTipContent {\n /** Accessible name for the affordance; defaults from the title. */\n ariaLabel?: string\n sx?: SxProps\n /** Forwarded to the icon button — e.g. to stop propagation when the tip\n * sits inside a clickable parent like an accordion summary. */\n onClick?: MouseEventHandler<HTMLElement>\n}\n\n/**\n * Unobtrusive question-mark help affordance: hover for a brief explanation,\n * click (when `href` is set) to open the documentation page in a new tab.\n * The shared primitive behind the console's docs help system (AGL-599..601).\n */\nexport function HelpTip(props: HelpTipProps) {\n const { excerpt, title, href, ariaLabel, sx, onClick } = props\n\n const label =\n ariaLabel ??\n (typeof title === 'string' ? `Help: ${title}` : 'Help')\n\n // Popper places the tooltip when it opens, and recomputes only on scroll, on\n // a window resize, or when the popper component itself re-renders. The\n // content can still grow after that — a console excerpt is a chunk fetched\n // on first open (AGL-2706) — and a tip placed at its title-only width then\n // widens from where it was put, off the screen at the right edge (AGL-2855).\n // So the open content reports its own size changes to the popper.\n const popper = useRef<PlacedPopper | null>(null)\n const setPopper = useCallback((instance: PlacedPopper | null) => {\n popper.current = instance\n }, [])\n const contentObserver = useRef<ResizeObserver | null>(null)\n const observeContent = useCallback((node: HTMLDivElement | null) => {\n contentObserver.current?.disconnect()\n contentObserver.current = null\n // No ResizeObserver means no layout to follow (jsdom).\n if (!node || typeof ResizeObserver === 'undefined') return\n contentObserver.current = new ResizeObserver(() => {\n void popper.current?.update()\n })\n contentObserver.current.observe(node)\n }, [])\n\n const content = (\n <Stack ref={observeContent} spacing={0.5} sx={{ p: 0.5, maxWidth: 280 }}>\n {title ? (\n <Typography variant=\"subtitle2\" component=\"span\">\n {title}\n </Typography>\n ) : null}\n <Typography variant=\"caption\" component=\"span\">\n {excerpt}\n </Typography>\n {href ? (\n <Link\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n variant=\"caption\"\n sx={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 0.5,\n color: 'inherit',\n fontWeight: 600,\n }}\n >\n Open documentation\n <MdiIcon path={mdiOpenInNew.path} sx={{ fontSize: '1em' }} />\n </Link>\n ) : null}\n </Stack>\n )\n\n const iconSx = mergeSxProps(\n {\n color: 'text.disabled',\n ':hover': { color: 'text.secondary' },\n },\n sx,\n )\n\n return (\n <Tooltip\n arrow\n enterDelay={150}\n title={content}\n slotProps={{ popper: { popperRef: setPopper } }}\n >\n {href ? (\n <IconButton\n component=\"a\"\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n size=\"small\"\n aria-label={`${label} — open documentation in a new tab`}\n sx={iconSx}\n onClick={onClick}\n >\n <MdiIcon path={mdiHelpCircleOutline.path} fontSize=\"inherit\" />\n </IconButton>\n ) : (\n <IconButton\n size=\"small\"\n aria-label={label}\n sx={iconSx}\n onClick={onClick}\n >\n <MdiIcon path={mdiHelpCircleOutline.path} fontSize=\"inherit\" />\n </IconButton>\n )}\n </Tooltip>\n )\n}\nHelpTip.displayName = 'HelpTip'\nHelpTip.aglyn = true\n\nexport default HelpTip\n"],"names":["mdiHelpCircleOutline","mdiOpenInNew","mergeSxProps","IconButton","Link","Stack","Tooltip","Typography","useCallback","useRef","MdiIcon","HelpTip","props","excerpt","title","href","ariaLabel","sx","onClick","label","popper","setPopper","instance","current","contentObserver","observeContent","node","disconnect","ResizeObserver","update","observe","content","ref","spacing","p","maxWidth","variant","component","target","rel","display","alignItems","gap","color","fontWeight","path","fontSize","iconSx","arrow","enterDelay","slotProps","popperRef","size","aria-label","displayName","aglyn"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAASA,oBAAoB,EAAEC,YAAY,QAAQ,yBAAwB;AAC3E,SAASC,YAAY,QAAQ,yBAAwB;AACrD,SACEC,UAAU,EACVC,IAAI,EACJC,KAAK,EAELC,OAAO,EACPC,UAAU,QACL,gBAAe;AACtB,SAASC,WAAW,EAAEC,MAAM,QAAQ,QAAO;AAE3C,SAASC,OAAO,QAAQ,yBAAqB;AA0B7C;;;;CAIC,GACD,OAAO,SAASC,QAAQC,KAAmB;IACzC,MAAM,EAAEC,OAAO,EAAEC,KAAK,EAAEC,IAAI,EAAEC,SAAS,EAAEC,EAAE,EAAEC,OAAO,EAAE,GAAGN;IAEzD,MAAMO,QACJH,oBAAAA,YACC,OAAOF,UAAU,WAAW,CAAC,MAAM,EAAEA,OAAO,GAAG;IAElD,6EAA6E;IAC7E,uEAAuE;IACvE,2EAA2E;IAC3E,2EAA2E;IAC3E,6EAA6E;IAC7E,kEAAkE;IAClE,MAAMM,SAASX,OAA4B;IAC3C,MAAMY,YAAYb,YAAY,CAACc;QAC7BF,OAAOG,OAAO,GAAGD;IACnB,GAAG,EAAE;IACL,MAAME,kBAAkBf,OAA8B;IACtD,MAAMgB,iBAAiBjB,YAAY,CAACkB;YAClCF;SAAAA,2BAAAA,gBAAgBD,OAAO,qBAAvBC,yBAAyBG,UAAU;QACnCH,gBAAgBD,OAAO,GAAG;QAC1B,uDAAuD;QACvD,IAAI,CAACG,QAAQ,OAAOE,mBAAmB,aAAa;QACpDJ,gBAAgBD,OAAO,GAAG,IAAIK,eAAe;gBACtCR;YAAL,OAAKA,kBAAAA,OAAOG,OAAO,qBAAdH,gBAAgBS,MAAM;QAC7B;QACAL,gBAAgBD,OAAO,CAACO,OAAO,CAACJ;IAClC,GAAG,EAAE;IAEL,MAAMK,wBACJ,MAAC1B;QAAM2B,KAAKP;QAAgBQ,SAAS;QAAKhB,IAAI;YAAEiB,GAAG;YAAKC,UAAU;QAAI;;YACnErB,sBACC,KAACP;gBAAW6B,SAAQ;gBAAYC,WAAU;0BACvCvB;iBAED;0BACJ,KAACP;gBAAW6B,SAAQ;gBAAUC,WAAU;0BACrCxB;;YAEFE,qBACC,MAACX;gBACCW,MAAMA;gBACNuB,QAAO;gBACPC,KAAI;gBACJH,SAAQ;gBACRnB,IAAI;oBACFuB,SAAS;oBACTC,YAAY;oBACZC,KAAK;oBACLC,OAAO;oBACPC,YAAY;gBACd;;oBACD;kCAEC,KAAClC;wBAAQmC,MAAM5C,aAAa4C,IAAI;wBAAE5B,IAAI;4BAAE6B,UAAU;wBAAM;;;iBAExD;;;IAIR,MAAMC,SAAS7C,aACb;QACEyC,OAAO;QACP,UAAU;YAAEA,OAAO;QAAiB;IACtC,GACA1B;IAGF,qBACE,KAACX;QACC0C,KAAK;QACLC,YAAY;QACZnC,OAAOiB;QACPmB,WAAW;YAAE9B,QAAQ;gBAAE+B,WAAW9B;YAAU;QAAE;kBAE7CN,qBACC,KAACZ;YACCkC,WAAU;YACVtB,MAAMA;YACNuB,QAAO;YACPC,KAAI;YACJa,MAAK;YACLC,cAAY,GAAGlC,MAAM,kCAAkC,CAAC;YACxDF,IAAI8B;YACJ7B,SAASA;sBAET,cAAA,KAACR;gBAAQmC,MAAM7C,qBAAqB6C,IAAI;gBAAEC,UAAS;;2BAGrD,KAAC3C;YACCiD,MAAK;YACLC,cAAYlC;YACZF,IAAI8B;YACJ7B,SAASA;sBAET,cAAA,KAACR;gBAAQmC,MAAM7C,qBAAqB6C,IAAI;gBAAEC,UAAS;;;;AAK7D;AACAnC,QAAQ2C,WAAW,GAAG;AACtB3C,QAAQ4C,KAAK,GAAG;AAEhB,eAAe5C,QAAO"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridges a Next.js `<Link>`'s real navigation transition state
|
|
3
|
+
* (`useLinkStatus`, Next 15.3+/16) to the global loading overlay.
|
|
4
|
+
*
|
|
5
|
+
* Rendered as a child of every `<Link>` (via {@link NextLink}). `useLinkStatus`
|
|
6
|
+
* reads the *enclosing* link's own status context, so only the clicked link's
|
|
7
|
+
* reporter goes `pending` — exactly one overlay is queued per navigation, and
|
|
8
|
+
* it stays queued until the destination route is genuinely ready (through slow
|
|
9
|
+
* dev compiles / RSC fetches).
|
|
10
|
+
*
|
|
11
|
+
* This replaces the old `usePathname`/`useSearchParams` heuristic, which
|
|
12
|
+
* settled the overlay on URL *commit* — before a slow segment had finished
|
|
13
|
+
* fetching/compiling — so the modal flashed away while the user was still
|
|
14
|
+
* waiting for the real 200.
|
|
15
|
+
*
|
|
16
|
+
* `useLoading()` returns a no-op context when no `LoadingProvider` sits above
|
|
17
|
+
* it, so this is safe for links rendered outside an app shell.
|
|
18
|
+
*/
|
|
19
|
+
export declare function LinkNavigationReporter(): null;
|
|
20
|
+
export declare namespace LinkNavigationReporter {
|
|
21
|
+
var displayName: string;
|
|
22
|
+
var aglyn: boolean;
|
|
23
|
+
}
|
|
24
|
+
export default LinkNavigationReporter;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { useLinkStatus } from "next/link";
|
|
18
|
+
import { useEffect, useRef } from "react";
|
|
19
|
+
import { useLoading } from "../contexts/loading.context.js";
|
|
20
|
+
/**
|
|
21
|
+
* Bridges a Next.js `<Link>`'s real navigation transition state
|
|
22
|
+
* (`useLinkStatus`, Next 15.3+/16) to the global loading overlay.
|
|
23
|
+
*
|
|
24
|
+
* Rendered as a child of every `<Link>` (via {@link NextLink}). `useLinkStatus`
|
|
25
|
+
* reads the *enclosing* link's own status context, so only the clicked link's
|
|
26
|
+
* reporter goes `pending` — exactly one overlay is queued per navigation, and
|
|
27
|
+
* it stays queued until the destination route is genuinely ready (through slow
|
|
28
|
+
* dev compiles / RSC fetches).
|
|
29
|
+
*
|
|
30
|
+
* This replaces the old `usePathname`/`useSearchParams` heuristic, which
|
|
31
|
+
* settled the overlay on URL *commit* — before a slow segment had finished
|
|
32
|
+
* fetching/compiling — so the modal flashed away while the user was still
|
|
33
|
+
* waiting for the real 200.
|
|
34
|
+
*
|
|
35
|
+
* `useLoading()` returns a no-op context when no `LoadingProvider` sits above
|
|
36
|
+
* it, so this is safe for links rendered outside an app shell.
|
|
37
|
+
*/ export function LinkNavigationReporter() {
|
|
38
|
+
const { pending } = useLinkStatus();
|
|
39
|
+
const { queueLoading } = useLoading();
|
|
40
|
+
const dequeueRef = useRef(null);
|
|
41
|
+
useEffect(()=>{
|
|
42
|
+
if (pending) {
|
|
43
|
+
// Guard against re-queuing while a navigation is already in flight.
|
|
44
|
+
if (!dequeueRef.current) dequeueRef.current = queueLoading();
|
|
45
|
+
} else {
|
|
46
|
+
dequeueRef.current == null ? void 0 : dequeueRef.current.call(dequeueRef);
|
|
47
|
+
dequeueRef.current = null;
|
|
48
|
+
}
|
|
49
|
+
}, [
|
|
50
|
+
pending,
|
|
51
|
+
queueLoading
|
|
52
|
+
]);
|
|
53
|
+
// If the link unmounts mid-navigation, never leave the overlay wedged.
|
|
54
|
+
useEffect(()=>()=>{
|
|
55
|
+
dequeueRef.current == null ? void 0 : dequeueRef.current.call(dequeueRef);
|
|
56
|
+
dequeueRef.current = null;
|
|
57
|
+
}, []);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
LinkNavigationReporter.displayName = 'LinkNavigationReporter';
|
|
61
|
+
LinkNavigationReporter.aglyn = true;
|
|
62
|
+
export default LinkNavigationReporter;
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=link-navigation-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/components/link-navigation-reporter.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { useLinkStatus } from 'next/link'\nimport { useEffect, useRef } from 'react'\nimport { useLoading } from '../contexts/loading.context'\n\n/**\n * Bridges a Next.js `<Link>`'s real navigation transition state\n * (`useLinkStatus`, Next 15.3+/16) to the global loading overlay.\n *\n * Rendered as a child of every `<Link>` (via {@link NextLink}). `useLinkStatus`\n * reads the *enclosing* link's own status context, so only the clicked link's\n * reporter goes `pending` — exactly one overlay is queued per navigation, and\n * it stays queued until the destination route is genuinely ready (through slow\n * dev compiles / RSC fetches).\n *\n * This replaces the old `usePathname`/`useSearchParams` heuristic, which\n * settled the overlay on URL *commit* — before a slow segment had finished\n * fetching/compiling — so the modal flashed away while the user was still\n * waiting for the real 200.\n *\n * `useLoading()` returns a no-op context when no `LoadingProvider` sits above\n * it, so this is safe for links rendered outside an app shell.\n */\nexport function LinkNavigationReporter(): null {\n const { pending } = useLinkStatus()\n const { queueLoading } = useLoading()\n const dequeueRef = useRef<(() => void) | null>(null)\n\n useEffect(() => {\n if (pending) {\n // Guard against re-queuing while a navigation is already in flight.\n if (!dequeueRef.current) dequeueRef.current = queueLoading()\n } else {\n dequeueRef.current?.()\n dequeueRef.current = null\n }\n }, [pending, queueLoading])\n\n // If the link unmounts mid-navigation, never leave the overlay wedged.\n useEffect(\n () => () => {\n dequeueRef.current?.()\n dequeueRef.current = null\n },\n [],\n )\n\n return null\n}\n\nLinkNavigationReporter.displayName = 'LinkNavigationReporter'\nLinkNavigationReporter.aglyn = true\n\nexport default LinkNavigationReporter\n"],"names":["useLinkStatus","useEffect","useRef","useLoading","LinkNavigationReporter","pending","queueLoading","dequeueRef","current","displayName","aglyn"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SAASA,aAAa,QAAQ,YAAW;AACzC,SAASC,SAAS,EAAEC,MAAM,QAAQ,QAAO;AACzC,SAASC,UAAU,QAAQ,iCAA6B;AAExD;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASC;IACd,MAAM,EAAEC,OAAO,EAAE,GAAGL;IACpB,MAAM,EAAEM,YAAY,EAAE,GAAGH;IACzB,MAAMI,aAAaL,OAA4B;IAE/CD,UAAU;QACR,IAAII,SAAS;YACX,oEAAoE;YACpE,IAAI,CAACE,WAAWC,OAAO,EAAED,WAAWC,OAAO,GAAGF;QAChD,OAAO;YACLC,WAAWC,OAAO,oBAAlBD,WAAWC,OAAO,MAAlBD;YACAA,WAAWC,OAAO,GAAG;QACvB;IACF,GAAG;QAACH;QAASC;KAAa;IAE1B,uEAAuE;IACvEL,UACE,IAAM;YACJM,WAAWC,OAAO,oBAAlBD,WAAWC,OAAO,MAAlBD;YACAA,WAAWC,OAAO,GAAG;QACvB,GACA,EAAE;IAGJ,OAAO;AACT;AAEAJ,uBAAuBK,WAAW,GAAG;AACrCL,uBAAuBM,KAAK,GAAG;AAE/B,eAAeN,uBAAsB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { TablePaginationProps } from '@mui/material/TablePagination';
|
|
2
|
+
export interface ListPaginationProps {
|
|
3
|
+
/** Zero-based, like MUI's own. */
|
|
4
|
+
page: number;
|
|
5
|
+
pageSize: number;
|
|
6
|
+
/** Rows rendered on the CURRENT page — not the collection's total. */
|
|
7
|
+
rowCount: number;
|
|
8
|
+
onPageChange: (page: number) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Omit on a list whose page size is not the reader's to choose — the size
|
|
11
|
+
* menu is then not rendered at all. Most lists should pass it.
|
|
12
|
+
*/
|
|
13
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
14
|
+
/**
|
|
15
|
+
* The collection's total, when the caller genuinely knows it — a
|
|
16
|
+
* client-side list, or a server `count()`. Leave undefined for a cursor or
|
|
17
|
+
* growing-window feed, where nobody knows it without paying for it.
|
|
18
|
+
*/
|
|
19
|
+
count?: number;
|
|
20
|
+
/** Cursor/window feeds: whether a further page exists. */
|
|
21
|
+
hasMore?: boolean;
|
|
22
|
+
/** Override the count line, e.g. the screens tree's "top-level screens". */
|
|
23
|
+
labelDisplayedRows?: TablePaginationProps['labelDisplayedRows'];
|
|
24
|
+
pageSizeOptions?: number[];
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The footer under every paginated list, whatever is behind it.
|
|
29
|
+
*
|
|
30
|
+
* The console grew four pagination grammars — a MUI X `DataGrid` footer, a
|
|
31
|
+
* hand-rolled `TablePagination`, a bare Previous/Next button pair, and a
|
|
32
|
+
* "Load more" that only ever grew — so the same act took a different control
|
|
33
|
+
* depending on which list a reader was standing in, and two of the four
|
|
34
|
+
* offered no way to change the page size at all. This is the one control.
|
|
35
|
+
*
|
|
36
|
+
* ## Counting without a count
|
|
37
|
+
*
|
|
38
|
+
* A cursor feed cannot say how many rows exist without reading them, which is
|
|
39
|
+
* the cost pagination is there to avoid. MUI already models this: `count={-1}`
|
|
40
|
+
* renders "1–10 of more than 10" and leaves Next live.
|
|
41
|
+
*
|
|
42
|
+
* The trick is the LAST page, where the total stops being unknown — once no
|
|
43
|
+
* further page exists, `page × pageSize + rowCount` IS the total. Handing MUI
|
|
44
|
+
* the real number there is what disables Next, so the control needs no
|
|
45
|
+
* per-version knowledge of how to reach inside and disable that button. The
|
|
46
|
+
* count line also stops saying "more than" at exactly the point it would
|
|
47
|
+
* become a lie.
|
|
48
|
+
*
|
|
49
|
+
* `DataGrid` keeps its own footer — it renders one internally and cannot be
|
|
50
|
+
* given this — but it is fed the same options, default and label from
|
|
51
|
+
* `const/table-pagination`, so the two read identically.
|
|
52
|
+
*/
|
|
53
|
+
export declare function ListPagination(props: ListPaginationProps): import("react").JSX.Element;
|
|
54
|
+
export declare namespace ListPagination {
|
|
55
|
+
var displayName: string;
|
|
56
|
+
}
|
|
57
|
+
export default ListPagination;
|