@fgv/ts-app-shell 5.1.0-3 → 5.1.0-30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/packlets/ai-assist/index.js.map +1 -0
- package/dist/packlets/ai-assist/useAiAssist.js +216 -15
- package/dist/packlets/ai-assist/useAiAssist.js.map +1 -0
- package/dist/packlets/badge/index.js +23 -0
- package/dist/packlets/badge/index.js.map +1 -0
- package/dist/packlets/badge/renderStatusBadge.js +44 -0
- package/dist/packlets/badge/renderStatusBadge.js.map +1 -0
- package/dist/packlets/cascade/CascadeContainer.js.map +1 -0
- package/dist/packlets/cascade/ComparisonView.js.map +1 -0
- package/dist/packlets/cascade/EntityTabLayout.js.map +1 -0
- package/dist/packlets/cascade/MobileCascadeStack.js.map +1 -0
- package/dist/packlets/cascade/index.js.map +1 -0
- package/dist/packlets/cascade/model.js.map +1 -0
- package/dist/packlets/cascade/useCascadeOps.js.map +1 -0
- package/dist/packlets/cascade/useCascadeTransitions.js.map +1 -0
- package/dist/packlets/detail/DetailHelpers.js.map +1 -0
- package/dist/packlets/detail/index.js.map +1 -0
- package/dist/packlets/drop-zone/JsonDropZone.js.map +1 -0
- package/dist/packlets/drop-zone/index.js.map +1 -0
- package/dist/packlets/editing/EditFieldHelpers.js +4 -4
- package/dist/packlets/editing/EditFieldHelpers.js.map +1 -0
- package/dist/packlets/editing/MultiActionButton.js.map +1 -0
- package/dist/packlets/editing/NumericInput.js.map +1 -0
- package/dist/packlets/editing/TypeaheadInput.js.map +1 -0
- package/dist/packlets/editing/index.js.map +1 -0
- package/dist/packlets/editing/useTypeaheadMatch.js.map +1 -0
- package/dist/packlets/keyboard/index.js.map +1 -0
- package/dist/packlets/keyboard/registry.js.map +1 -0
- package/dist/packlets/keyboard/useKeyboardShortcuts.js.map +1 -0
- package/dist/packlets/messages/MessagesContext.js.map +1 -0
- package/dist/packlets/messages/MessagesLogger.js.map +1 -0
- package/dist/packlets/messages/StatusBar.js.map +1 -0
- package/dist/packlets/messages/Toast.js.map +1 -0
- package/dist/packlets/messages/index.js.map +1 -0
- package/dist/packlets/messages/model.js.map +1 -0
- package/dist/packlets/messages/useLogReporter.js.map +1 -0
- package/dist/packlets/modal/ConfirmDialog.js.map +1 -0
- package/dist/packlets/modal/Modal.js.map +1 -0
- package/dist/packlets/modal/index.js.map +1 -0
- package/dist/packlets/print/PrintEnclosure.js.map +1 -0
- package/dist/packlets/print/index.js.map +1 -0
- package/dist/packlets/print/openPrintWindow.js.map +1 -0
- package/dist/packlets/responsive/ResponsiveProvider.js.map +1 -0
- package/dist/packlets/responsive/index.js.map +1 -0
- package/dist/packlets/responsive/useResponsiveLayout.js.map +1 -0
- package/dist/packlets/selectors/EntityRow.js.map +1 -0
- package/dist/packlets/selectors/PreferredSelector.js.map +1 -0
- package/dist/packlets/selectors/index.js.map +1 -0
- package/dist/packlets/sidebar/CollectionSection.js +158 -43
- package/dist/packlets/sidebar/CollectionSection.js.map +1 -0
- package/dist/packlets/sidebar/EntityList.js.map +1 -0
- package/dist/packlets/sidebar/FilterBar.js.map +1 -0
- package/dist/packlets/sidebar/FilterRow.js.map +1 -0
- package/dist/packlets/sidebar/GroupedEntityList.js.map +1 -0
- package/dist/packlets/sidebar/SearchBar.js.map +1 -0
- package/dist/packlets/sidebar/SidebarLayout.js.map +1 -0
- package/dist/packlets/sidebar/index.js.map +1 -0
- package/dist/packlets/theme/ThemeProvider.js.map +1 -0
- package/dist/packlets/theme/index.js.map +1 -0
- package/dist/packlets/top-bar/ModeSelector.js.map +1 -0
- package/dist/packlets/top-bar/TabBar.js +4 -1
- package/dist/packlets/top-bar/TabBar.js.map +1 -0
- package/dist/packlets/top-bar/index.js.map +1 -0
- package/dist/packlets/url-sync/index.js.map +1 -0
- package/dist/packlets/url-sync/useUrlSync.js.map +1 -0
- package/dist/styles/theme.css +194 -0
- package/lib/index.browser.d.ts.map +1 -0
- package/lib/index.browser.js.map +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js.map +1 -0
- package/lib/packlets/ai-assist/index.d.ts.map +1 -0
- package/lib/packlets/ai-assist/index.js.map +1 -0
- package/lib/packlets/ai-assist/useAiAssist.d.ts +26 -0
- package/lib/packlets/ai-assist/useAiAssist.d.ts.map +1 -0
- package/lib/packlets/ai-assist/useAiAssist.js +216 -15
- package/lib/packlets/ai-assist/useAiAssist.js.map +1 -0
- package/lib/packlets/badge/index.d.ts +2 -0
- package/lib/packlets/badge/index.d.ts.map +1 -0
- package/lib/packlets/badge/index.js +27 -0
- package/lib/packlets/badge/index.js.map +1 -0
- package/lib/packlets/badge/renderStatusBadge.d.ts +11 -0
- package/lib/packlets/badge/renderStatusBadge.d.ts.map +1 -0
- package/lib/packlets/badge/renderStatusBadge.js +50 -0
- package/lib/packlets/badge/renderStatusBadge.js.map +1 -0
- package/lib/packlets/cascade/CascadeContainer.d.ts.map +1 -0
- package/lib/packlets/cascade/CascadeContainer.js.map +1 -0
- package/lib/packlets/cascade/ComparisonView.d.ts.map +1 -0
- package/lib/packlets/cascade/ComparisonView.js.map +1 -0
- package/lib/packlets/cascade/EntityTabLayout.d.ts.map +1 -0
- package/lib/packlets/cascade/EntityTabLayout.js.map +1 -0
- package/lib/packlets/cascade/MobileCascadeStack.d.ts.map +1 -0
- package/lib/packlets/cascade/MobileCascadeStack.js.map +1 -0
- package/lib/packlets/cascade/index.d.ts.map +1 -0
- package/lib/packlets/cascade/index.js.map +1 -0
- package/lib/packlets/cascade/model.d.ts.map +1 -0
- package/lib/packlets/cascade/model.js.map +1 -0
- package/lib/packlets/cascade/useCascadeOps.d.ts.map +1 -0
- package/lib/packlets/cascade/useCascadeOps.js.map +1 -0
- package/lib/packlets/cascade/useCascadeTransitions.d.ts.map +1 -0
- package/lib/packlets/cascade/useCascadeTransitions.js.map +1 -0
- package/lib/packlets/detail/DetailHelpers.d.ts.map +1 -0
- package/lib/packlets/detail/DetailHelpers.js.map +1 -0
- package/lib/packlets/detail/index.d.ts.map +1 -0
- package/lib/packlets/detail/index.js.map +1 -0
- package/lib/packlets/drop-zone/JsonDropZone.d.ts.map +1 -0
- package/lib/packlets/drop-zone/JsonDropZone.js.map +1 -0
- package/lib/packlets/drop-zone/index.d.ts.map +1 -0
- package/lib/packlets/drop-zone/index.js.map +1 -0
- package/lib/packlets/editing/EditFieldHelpers.d.ts +6 -2
- package/lib/packlets/editing/EditFieldHelpers.d.ts.map +1 -0
- package/lib/packlets/editing/EditFieldHelpers.js +4 -4
- package/lib/packlets/editing/EditFieldHelpers.js.map +1 -0
- package/lib/packlets/editing/MultiActionButton.d.ts.map +1 -0
- package/lib/packlets/editing/MultiActionButton.js.map +1 -0
- package/lib/packlets/editing/NumericInput.d.ts.map +1 -0
- package/lib/packlets/editing/NumericInput.js.map +1 -0
- package/lib/packlets/editing/TypeaheadInput.d.ts.map +1 -0
- package/lib/packlets/editing/TypeaheadInput.js.map +1 -0
- package/lib/packlets/editing/index.d.ts.map +1 -0
- package/lib/packlets/editing/index.js.map +1 -0
- package/lib/packlets/editing/useTypeaheadMatch.d.ts.map +1 -0
- package/lib/packlets/editing/useTypeaheadMatch.js.map +1 -0
- package/lib/packlets/keyboard/index.d.ts.map +1 -0
- package/lib/packlets/keyboard/index.js.map +1 -0
- package/lib/packlets/keyboard/registry.d.ts.map +1 -0
- package/lib/packlets/keyboard/registry.js.map +1 -0
- package/lib/packlets/keyboard/useKeyboardShortcuts.d.ts.map +1 -0
- package/lib/packlets/keyboard/useKeyboardShortcuts.js.map +1 -0
- package/lib/packlets/messages/MessagesContext.d.ts.map +1 -0
- package/lib/packlets/messages/MessagesContext.js.map +1 -0
- package/lib/packlets/messages/MessagesLogger.d.ts.map +1 -0
- package/lib/packlets/messages/MessagesLogger.js.map +1 -0
- package/lib/packlets/messages/StatusBar.d.ts.map +1 -0
- package/lib/packlets/messages/StatusBar.js.map +1 -0
- package/lib/packlets/messages/Toast.d.ts.map +1 -0
- package/lib/packlets/messages/Toast.js.map +1 -0
- package/lib/packlets/messages/index.d.ts.map +1 -0
- package/lib/packlets/messages/index.js.map +1 -0
- package/lib/packlets/messages/model.d.ts.map +1 -0
- package/lib/packlets/messages/model.js.map +1 -0
- package/lib/packlets/messages/useLogReporter.d.ts.map +1 -0
- package/lib/packlets/messages/useLogReporter.js.map +1 -0
- package/lib/packlets/modal/ConfirmDialog.d.ts.map +1 -0
- package/lib/packlets/modal/ConfirmDialog.js.map +1 -0
- package/lib/packlets/modal/Modal.d.ts.map +1 -0
- package/lib/packlets/modal/Modal.js.map +1 -0
- package/lib/packlets/modal/index.d.ts.map +1 -0
- package/lib/packlets/modal/index.js.map +1 -0
- package/lib/packlets/print/PrintEnclosure.d.ts.map +1 -0
- package/lib/packlets/print/PrintEnclosure.js.map +1 -0
- package/lib/packlets/print/index.d.ts.map +1 -0
- package/lib/packlets/print/index.js.map +1 -0
- package/lib/packlets/print/openPrintWindow.d.ts.map +1 -0
- package/lib/packlets/print/openPrintWindow.js.map +1 -0
- package/lib/packlets/responsive/ResponsiveProvider.d.ts.map +1 -0
- package/lib/packlets/responsive/ResponsiveProvider.js.map +1 -0
- package/lib/packlets/responsive/index.d.ts.map +1 -0
- package/lib/packlets/responsive/index.js.map +1 -0
- package/lib/packlets/responsive/useResponsiveLayout.d.ts.map +1 -0
- package/lib/packlets/responsive/useResponsiveLayout.js.map +1 -0
- package/lib/packlets/selectors/EntityRow.d.ts.map +1 -0
- package/lib/packlets/selectors/EntityRow.js.map +1 -0
- package/lib/packlets/selectors/PreferredSelector.d.ts.map +1 -0
- package/lib/packlets/selectors/PreferredSelector.js.map +1 -0
- package/lib/packlets/selectors/index.d.ts.map +1 -0
- package/lib/packlets/selectors/index.js.map +1 -0
- package/lib/packlets/sidebar/CollectionSection.d.ts +40 -2
- package/lib/packlets/sidebar/CollectionSection.d.ts.map +1 -0
- package/lib/packlets/sidebar/CollectionSection.js +157 -42
- package/lib/packlets/sidebar/CollectionSection.js.map +1 -0
- package/lib/packlets/sidebar/EntityList.d.ts.map +1 -0
- package/lib/packlets/sidebar/EntityList.js.map +1 -0
- package/lib/packlets/sidebar/FilterBar.d.ts.map +1 -0
- package/lib/packlets/sidebar/FilterBar.js.map +1 -0
- package/lib/packlets/sidebar/FilterRow.d.ts.map +1 -0
- package/lib/packlets/sidebar/FilterRow.js.map +1 -0
- package/lib/packlets/sidebar/GroupedEntityList.d.ts.map +1 -0
- package/lib/packlets/sidebar/GroupedEntityList.js.map +1 -0
- package/lib/packlets/sidebar/SearchBar.d.ts.map +1 -0
- package/lib/packlets/sidebar/SearchBar.js.map +1 -0
- package/lib/packlets/sidebar/SidebarLayout.d.ts.map +1 -0
- package/lib/packlets/sidebar/SidebarLayout.js.map +1 -0
- package/lib/packlets/sidebar/index.d.ts +1 -1
- package/lib/packlets/sidebar/index.d.ts.map +1 -0
- package/lib/packlets/sidebar/index.js.map +1 -0
- package/lib/packlets/theme/ThemeProvider.d.ts.map +1 -0
- package/lib/packlets/theme/ThemeProvider.js.map +1 -0
- package/lib/packlets/theme/index.d.ts.map +1 -0
- package/lib/packlets/theme/index.js.map +1 -0
- package/lib/packlets/top-bar/ModeSelector.d.ts.map +1 -0
- package/lib/packlets/top-bar/ModeSelector.js.map +1 -0
- package/lib/packlets/top-bar/TabBar.d.ts +12 -0
- package/lib/packlets/top-bar/TabBar.d.ts.map +1 -0
- package/lib/packlets/top-bar/TabBar.js +4 -1
- package/lib/packlets/top-bar/TabBar.js.map +1 -0
- package/lib/packlets/top-bar/index.d.ts +1 -1
- package/lib/packlets/top-bar/index.d.ts.map +1 -0
- package/lib/packlets/top-bar/index.js.map +1 -0
- package/lib/packlets/url-sync/index.d.ts.map +1 -0
- package/lib/packlets/url-sync/index.js.map +1 -0
- package/lib/packlets/url-sync/useUrlSync.d.ts.map +1 -0
- package/lib/packlets/url-sync/useUrlSync.js.map +1 -0
- package/lib/styles/theme.css +194 -0
- package/package.json +13 -9
- package/tailwind-preset.cjs +102 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeaheadInput.d.ts","sourceRoot":"","sources":["../../../src/packlets/editing/TypeaheadInput.tsx"],"names":[],"mappings":"AAsBA;;;;GAIG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,EAAE,KAAK,oBAAoB,EAAqB,MAAM,qBAAqB,CAAC;AAMnF;;;GAGG;AACH,MAAM,WAAW,oBAAoB,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IAC/D,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,0EAA0E;IAC1E,QAAQ,CAAC,mBAAmB,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;IACxE,2FAA2F;IAC3F,QAAQ,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,oBAAoB,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IACnE,qFAAqF;IACrF,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sCAAsC;IACtC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAMD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EACxD,KAAK,EAAE,oBAAoB,CAAC,GAAG,CAAC,GAC/B,KAAK,CAAC,YAAY,CAiRpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeaheadInput.js","sourceRoot":"","sources":["../../../src/packlets/editing/TypeaheadInput.tsx"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * TypeaheadInput — text input with custom autocomplete dropdown supporting\n * tiered suggestions and built-in blur resolution.\n * @packageDocumentation\n */\n\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { type ITypeaheadSuggestion, useTypeaheadMatch } from './useTypeaheadMatch';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Props for the TypeaheadInput component.\n * @public\n */\nexport interface ITypeaheadInputProps<TId extends string = string> {\n /** Current text value (controlled). */\n readonly value: string;\n /** Called on every keystroke. */\n readonly onChange: (value: string) => void;\n /** Full catalog of suggestions (lower priority). */\n readonly suggestions: ReadonlyArray<ITypeaheadSuggestion<TId>>;\n /** Optional priority suggestions shown first (e.g. recipe alternates). */\n readonly prioritySuggestions?: ReadonlyArray<ITypeaheadSuggestion<TId>>;\n /** Called when a suggestion is definitively selected (click, Enter, blur auto-resolve). */\n readonly onSelect: (suggestion: ITypeaheadSuggestion<TId>) => void;\n /** Called on blur/Enter/Tab when input cannot be resolved to a single suggestion. */\n readonly onUnresolved?: (text: string) => void;\n /** Placeholder text for the input. */\n readonly placeholder?: string;\n /** Additional CSS class for the input element. */\n readonly className?: string;\n /** If true, the input is disabled. */\n readonly disabled?: boolean;\n /** Maximum dropdown height in pixels. Default: 240. */\n readonly maxHeight?: number;\n /** If true, the input is focused on mount. */\n readonly autoFocus?: boolean;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * Text input with a custom autocomplete dropdown supporting tiered suggestions.\n *\n * Priority suggestions (e.g. recipe alternates) appear first, visually separated\n * from the full catalog. On blur, applies resolution logic: exact match → auto-select,\n * single partial match → auto-select, else fires `onUnresolved`.\n *\n * @public\n */\nexport function TypeaheadInput<TId extends string = string>(\n props: ITypeaheadInputProps<TId>\n): React.ReactElement {\n const {\n value,\n onChange,\n suggestions,\n prioritySuggestions,\n onSelect,\n onUnresolved,\n placeholder,\n className,\n disabled,\n maxHeight = 240,\n autoFocus\n } = props;\n\n const [isOpen, setIsOpen] = useState(false);\n const [focusIndex, setFocusIndex] = useState(-1);\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n const mouseDownOnDropdownRef = useRef(false);\n\n const matcher = useTypeaheadMatch(suggestions, prioritySuggestions);\n\n // ---- Filtered suggestions ----\n\n const filtered = useMemo(() => matcher.filterSuggestions(value), [matcher, value]);\n\n const flatItems = useMemo(\n () => [...filtered.priority, ...filtered.catalog],\n [filtered.priority, filtered.catalog]\n );\n\n const hasPriorityItems = filtered.priority.length > 0;\n const hasCatalogItems = filtered.catalog.length > 0;\n const hasItems = flatItems.length > 0;\n\n // Reset focus index when suggestions change\n useEffect(() => {\n setFocusIndex(-1);\n }, [value]);\n\n // Scroll focused item into view\n useEffect(() => {\n if (isOpen && focusIndex >= 0 && itemRefs.current[focusIndex]) {\n itemRefs.current[focusIndex]?.scrollIntoView({ block: 'nearest' });\n }\n }, [isOpen, focusIndex]);\n\n // Close dropdown on outside click\n useEffect(() => {\n if (!isOpen) return;\n const handler = (e: MouseEvent): void => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(e.target as Node) &&\n inputRef.current &&\n !inputRef.current.contains(e.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return (): void => {\n document.removeEventListener('mousedown', handler);\n };\n }, [isOpen]);\n\n // ---- Selection ----\n\n const handleSelect = useCallback(\n (item: ITypeaheadSuggestion<TId>): void => {\n onSelect(item);\n setIsOpen(false);\n setFocusIndex(-1);\n },\n [onSelect]\n );\n\n const handleResolve = useCallback(\n (text: string): void => {\n const trimmed = text.trim();\n if (!trimmed) {\n setIsOpen(false);\n return;\n }\n const match = matcher.resolveOnBlur(trimmed);\n if (match) {\n handleSelect(match);\n } else if (onUnresolved) {\n onUnresolved(trimmed);\n setIsOpen(false);\n } else {\n setIsOpen(false);\n }\n },\n [matcher, handleSelect, onUnresolved]\n );\n\n // ---- Input handlers ----\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>): void => {\n onChange(e.target.value);\n if (!isOpen) {\n setIsOpen(true);\n }\n },\n [onChange, isOpen]\n );\n\n const handleFocus = useCallback((): void => {\n inputRef.current?.select();\n if (hasItems) {\n setIsOpen(true);\n }\n }, [hasItems]);\n\n const handleBlur = useCallback((): void => {\n // Guard: don't resolve if user is clicking an item in the dropdown\n if (mouseDownOnDropdownRef.current) {\n mouseDownOnDropdownRef.current = false;\n return;\n }\n handleResolve(value);\n }, [value, handleResolve]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent): void => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' && hasItems) {\n e.preventDefault();\n setIsOpen(true);\n setFocusIndex(0);\n }\n return;\n }\n\n switch (e.key) {\n case 'Escape': {\n e.preventDefault();\n e.stopPropagation();\n setIsOpen(false);\n setFocusIndex(-1);\n break;\n }\n case 'ArrowDown': {\n e.preventDefault();\n setFocusIndex((prev) => (prev < flatItems.length - 1 ? prev + 1 : 0));\n break;\n }\n case 'ArrowUp': {\n e.preventDefault();\n setFocusIndex((prev) => (prev > 0 ? prev - 1 : flatItems.length - 1));\n break;\n }\n case 'Enter': {\n e.preventDefault();\n if (focusIndex >= 0 && focusIndex < flatItems.length) {\n handleSelect(flatItems[focusIndex]);\n } else {\n handleResolve(value);\n }\n break;\n }\n case 'Tab': {\n // Allow default tab behavior but resolve first\n handleResolve(value);\n break;\n }\n default:\n break;\n }\n },\n [isOpen, hasItems, flatItems, focusIndex, handleSelect, handleResolve, value]\n );\n\n // ---- Dropdown mouse guard ----\n\n const handleDropdownMouseDown = useCallback((): void => {\n mouseDownOnDropdownRef.current = true;\n }, []);\n\n // ---- Render ----\n\n const priorityEndIndex = filtered.priority.length;\n\n return (\n <div className=\"relative\">\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n autoFocus={autoFocus}\n className={\n className ??\n 'w-full px-2 py-1 text-sm border border-border rounded focus:outline-none focus:ring-1 focus:ring-focus-ring focus:border-focus-ring'\n }\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n />\n\n {isOpen && hasItems && (\n <div\n ref={dropdownRef}\n className=\"absolute z-50 mt-1 w-full bg-surface border border-border rounded-lg shadow-lg overflow-hidden\"\n style={{ maxHeight }}\n role=\"listbox\"\n onMouseDown={handleDropdownMouseDown}\n >\n <div className=\"overflow-y-auto\" style={{ maxHeight }}>\n {/* Priority items */}\n {hasPriorityItems &&\n filtered.priority.map((item, index) => {\n const isFocused = index === focusIndex;\n return (\n <button\n key={item.id}\n ref={(el): void => {\n itemRefs.current[index] = el;\n }}\n role=\"option\"\n aria-selected={isFocused}\n onClick={(): void => handleSelect(item)}\n className={`flex items-center w-full px-2.5 py-1.5 text-left text-sm transition-colors border-l-2 ${\n isFocused\n ? 'bg-surface-alt text-primary border-brand-primary/50'\n : 'text-secondary hover:bg-hover border-brand-primary/20'\n }`}\n >\n <span className=\"flex-1 min-w-0 truncate\">{item.name}</span>\n </button>\n );\n })}\n\n {/* Separator */}\n {hasPriorityItems && hasCatalogItems && <div className=\"border-t border-border my-0.5\" />}\n\n {/* Catalog items */}\n {hasCatalogItems &&\n filtered.catalog.map((item, catalogIndex) => {\n const flatIndex = priorityEndIndex + catalogIndex;\n const isFocused = flatIndex === focusIndex;\n return (\n <button\n key={item.id}\n ref={(el): void => {\n itemRefs.current[flatIndex] = el;\n }}\n role=\"option\"\n aria-selected={isFocused}\n onClick={(): void => handleSelect(item)}\n className={`flex items-center w-full px-2.5 py-1.5 text-left text-sm transition-colors ${\n isFocused ? 'bg-surface-alt text-primary' : 'text-secondary hover:bg-hover'\n }`}\n >\n <span className=\"flex-1 min-w-0 truncate\">{item.name}</span>\n </button>\n );\n })}\n </div>\n </div>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/editing/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,SAAS,EACT,KAAK,eAAe,EACpB,WAAW,EACX,KAAK,iBAAiB,EACtB,SAAS,EACT,KAAK,eAAe,EACpB,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,aAAa,EACb,KAAK,mBAAmB,EACxB,WAAW,EACX,KAAK,iBAAiB,EACtB,WAAW,EACX,KAAK,iBAAiB,EACtB,SAAS,EACT,KAAK,eAAe,EACpB,aAAa,EACb,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC9B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7E,OAAO,EACL,iBAAiB,EACjB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/editing/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uDAmB4B;AAlB1B,6GAAA,SAAS,OAAA;AAET,+GAAA,WAAW,OAAA;AAEX,6GAAA,SAAS,OAAA;AAET,qHAAA,iBAAiB,OAAA;AAEjB,iHAAA,aAAa,OAAA;AAEb,+GAAA,WAAW,OAAA;AAEX,+GAAA,WAAW,OAAA;AAEX,6GAAA,SAAS,OAAA;AAET,iHAAA,aAAa,OAAA;AAIf,yDAI6B;AAH3B,sHAAA,iBAAiB,OAAA;AAKnB,+CAAuE;AAA9D,4GAAA,YAAY,OAAA;AAErB,mDAA6E;AAApE,gHAAA,cAAc,OAAA;AAEvB,yDAK6B;AAJ3B,sHAAA,iBAAiB,OAAA","sourcesContent":["/**\n * Editing packlet - generic form field primitives for entity editors.\n * @packageDocumentation\n */\n\nexport {\n EditField,\n type IEditFieldProps,\n EditSection,\n type IEditSectionProps,\n TextInput,\n type ITextInputProps,\n OptionalTextInput,\n type IOptionalTextInputProps,\n TextAreaInput,\n type ITextAreaInputProps,\n NumberInput,\n type INumberInputProps,\n SelectInput,\n type ISelectInputProps,\n TagsInput,\n type ITagsInputProps,\n CheckboxInput,\n type ICheckboxInputProps\n} from './EditFieldHelpers';\n\nexport {\n MultiActionButton,\n type IMultiActionButtonProps,\n type IMultiActionButtonAction\n} from './MultiActionButton';\n\nexport { NumericInput, type INumericInputProps } from './NumericInput';\n\nexport { TypeaheadInput, type ITypeaheadInputProps } from './TypeaheadInput';\n\nexport {\n useTypeaheadMatch,\n type ITypeaheadSuggestion,\n type ITypeaheadMatchResult,\n type IFilteredSuggestions\n} from './useTypeaheadMatch';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTypeaheadMatch.d.ts","sourceRoot":"","sources":["../../../src/packlets/editing/useTypeaheadMatch.ts"],"names":[],"mappings":"AAiCA;;;GAGG;AACH,MAAM,WAAW,oBAAoB,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IAC/D,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB,CAAC,GAAG,SAAS,MAAM;IACtD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;CAC5D;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB,CAAC,GAAG,SAAS,MAAM;IACvD,iFAAiF;IACjF,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,oBAAoB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACzE,sFAAsF;IACtF,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,oBAAoB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACxE,yFAAyF;IACzF,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,oBAAoB,CAAC,GAAG,CAAC,CAAC;CACjE;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,SAAS,MAAM,EAClD,WAAW,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,EACrD,mBAAmB,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,GAC7D,qBAAqB,CAAC,GAAG,CAAC,CAmF5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTypeaheadMatch.js","sourceRoot":"","sources":["../../../src/packlets/editing/useTypeaheadMatch.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Reusable typeahead matching hook with tiered priority support.\n * @packageDocumentation\n */\n\nimport { useCallback, useMemo } from 'react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A suggestion entry for typeahead matching.\n * @public\n */\nexport interface ITypeaheadSuggestion<TId extends string = string> {\n readonly id: TId;\n readonly name: string;\n}\n\n/**\n * Filtered suggestions split by tier.\n * @public\n */\nexport interface IFilteredSuggestions<TId extends string> {\n readonly priority: ReadonlyArray<ITypeaheadSuggestion<TId>>;\n readonly catalog: ReadonlyArray<ITypeaheadSuggestion<TId>>;\n}\n\n/**\n * Result of the useTypeaheadMatch hook.\n * @public\n */\nexport interface ITypeaheadMatchResult<TId extends string> {\n /** Find an exact match by id or case-insensitive name. Checks priority first. */\n findExactMatch: (input: string) => ITypeaheadSuggestion<TId> | undefined;\n /** Resolve on blur: exact match → use it; single partial → use it; else undefined. */\n resolveOnBlur: (input: string) => ITypeaheadSuggestion<TId> | undefined;\n /** Filter suggestions by input text, returning priority and catalog tiers separately. */\n filterSuggestions: (input: string) => IFilteredSuggestions<TId>;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook that provides typeahead matching and filtering with tiered priority support.\n *\n * `findExactMatch` matches by exact id or case-insensitive name (checks priority first).\n * `resolveOnBlur` tries exact match, then single partial match (priority first).\n * `filterSuggestions` returns suggestions split by tier, filtered by substring match.\n *\n * @param suggestions - The full catalog of suggestions\n * @param prioritySuggestions - Optional priority suggestions shown first (e.g. recipe alternates)\n * @returns Match and filter functions\n * @public\n */\nexport function useTypeaheadMatch<TId extends string>(\n suggestions: ReadonlyArray<ITypeaheadSuggestion<TId>>,\n prioritySuggestions?: ReadonlyArray<ITypeaheadSuggestion<TId>>\n): ITypeaheadMatchResult<TId> {\n // Pre-compute priority IDs for efficient catalog deduplication\n const priorityIds = useMemo(\n () => new Set(prioritySuggestions?.map((s) => s.id) ?? []),\n [prioritySuggestions]\n );\n\n const findExactMatch = useCallback(\n (input: string): ITypeaheadSuggestion<TId> | undefined => {\n const trimmed = input.trim();\n if (!trimmed) return undefined;\n const lower = trimmed.toLowerCase();\n if (prioritySuggestions) {\n const match = prioritySuggestions.find((s) => s.id === trimmed || s.name.toLowerCase() === lower);\n if (match) return match;\n }\n return suggestions.find((s) => s.id === trimmed || s.name.toLowerCase() === lower);\n },\n [suggestions, prioritySuggestions]\n );\n\n const resolveOnBlur = useCallback(\n (input: string): ITypeaheadSuggestion<TId> | undefined => {\n const trimmed = input.trim();\n if (!trimmed) return undefined;\n const lower = trimmed.toLowerCase();\n\n // Try exact match (priority first, then all)\n if (prioritySuggestions) {\n const priorityExact = prioritySuggestions.find(\n (s) => s.id === trimmed || s.name.toLowerCase() === lower\n );\n if (priorityExact) return priorityExact;\n }\n\n const exact = suggestions.find((s) => s.id === trimmed || s.name.toLowerCase() === lower);\n if (exact) return exact;\n\n // Try partial match in priority suggestions first\n if (prioritySuggestions) {\n const priorityPartials = prioritySuggestions.filter(\n (s) => s.name.toLowerCase().includes(lower) || s.id.toLowerCase().includes(lower)\n );\n if (priorityPartials.length === 1) return priorityPartials[0];\n }\n\n // Fall back to partial match in all suggestions\n const partials = suggestions.filter(\n (s) => s.name.toLowerCase().includes(lower) || s.id.toLowerCase().includes(lower)\n );\n if (partials.length === 1) return partials[0];\n\n return undefined;\n },\n [suggestions, prioritySuggestions]\n );\n\n const filterSuggestions = useCallback(\n (input: string): IFilteredSuggestions<TId> => {\n const trimmed = input.trim();\n const lower = trimmed.toLowerCase();\n\n // No input — return all suggestions split by tier\n if (!trimmed) {\n return {\n priority: prioritySuggestions ?? [],\n catalog: suggestions.filter((s) => !priorityIds.has(s.id))\n };\n }\n\n // Filter by substring match\n const matchesSuggestion = (s: ITypeaheadSuggestion<TId>): boolean =>\n s.name.toLowerCase().includes(lower) || s.id.toLowerCase().includes(lower);\n\n const priority = prioritySuggestions?.filter(matchesSuggestion) ?? [];\n const catalog = suggestions.filter((s) => !priorityIds.has(s.id) && matchesSuggestion(s));\n\n return { priority, catalog };\n },\n [suggestions, prioritySuggestions, priorityIds]\n );\n\n return { findExactMatch, resolveOnBlur, filterSuggestions };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/keyboard/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,qBAAqB,EAC1B,wBAAwB,EACxB,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,KAAK,8BAA8B,EACnC,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/keyboard/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uCAMoB;AAFlB,oHAAA,wBAAwB,OAAA;AACxB,0GAAA,cAAc,OAAA;AAGhB,+DAKgC;AAH9B,gIAAA,wBAAwB,OAAA;AACxB,2HAAA,mBAAmB,OAAA;AACnB,4HAAA,oBAAoB,OAAA","sourcesContent":["/**\n * Keyboard shortcut packlet - registry, context, and hooks.\n * @packageDocumentation\n */\n\nexport {\n type IKeyBinding,\n type IShortcut,\n type IShortcutRegistration,\n KeyboardShortcutRegistry,\n matchesBinding\n} from './registry';\n\nexport {\n type IKeyboardShortcutProviderProps,\n KeyboardShortcutProvider,\n useKeyboardRegistry,\n useKeyboardShortcuts\n} from './useKeyboardShortcuts';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/packlets/keyboard/registry.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;GAUG;AAMH;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB;IACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,yBAAyB;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,sBAAsB;IACtB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;IACvC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;CACjC;AAMD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAMlF;AAMD;;;;;;;;GAQG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqC;IAChE,OAAO,CAAC,SAAS,CAA2C;IAC5D,OAAO,CAAC,OAAO,CAAa;IAE5B;;;;OAIG;IACI,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,qBAAqB;IAe3D;;OAEG;IACI,MAAM,IAAI,aAAa,CAAC,SAAS,CAAC;IAIzC;;;;OAIG;IACI,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IA2B9C;;OAEG;IACI,OAAO,IAAI,IAAI;IAKtB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,eAAe;CAMxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/packlets/keyboard/registry.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Keyboard shortcut registry infrastructure.\n *\n * Provides a centralized registry for keyboard shortcuts with:\n * - Modifier-aware key matching (Cmd/Ctrl, Shift, Alt)\n * - Priority-based handler resolution (higher priority wins)\n * - React hook for component-scoped shortcut registration\n * - Global listener that dispatches to registered handlers\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Describes a keyboard shortcut binding.\n * @public\n */\nexport interface IKeyBinding {\n /** The key (e.g., 'k', 'z', 'Escape'). Case-insensitive. */\n readonly key: string;\n /** Require Cmd (Mac) / Ctrl (Windows/Linux) */\n readonly meta?: boolean;\n /** Require Shift */\n readonly shift?: boolean;\n /** Require Alt/Option */\n readonly alt?: boolean;\n}\n\n/**\n * A registered keyboard shortcut.\n * @public\n */\nexport interface IShortcut {\n /** The key binding */\n readonly binding: IKeyBinding;\n /** Human-readable description (for command palette / help) */\n readonly description: string;\n /** Handler function. Return true to indicate the event was handled. */\n readonly handler: () => boolean | void;\n /** Priority (higher wins when multiple shortcuts match). Default: 0 */\n readonly priority?: number;\n}\n\n/**\n * A registration handle returned when a shortcut is registered.\n * Call `unregister()` to remove the shortcut.\n * @public\n */\nexport interface IShortcutRegistration {\n readonly unregister: () => void;\n}\n\n// ============================================================================\n// Key Matching\n// ============================================================================\n\n/**\n * Tests whether a keyboard event matches a key binding.\n * @param event - The keyboard event\n * @param binding - The binding to match against\n * @returns true if the event matches\n * @public\n */\nexport function matchesBinding(event: KeyboardEvent, binding: IKeyBinding): boolean {\n const keyMatch = event.key.toLowerCase() === binding.key.toLowerCase();\n const metaMatch = (binding.meta ?? false) === (event.metaKey || event.ctrlKey);\n const shiftMatch = (binding.shift ?? false) === event.shiftKey;\n const altMatch = (binding.alt ?? false) === event.altKey;\n return keyMatch && metaMatch && shiftMatch && altMatch;\n}\n\n// ============================================================================\n// Registry\n// ============================================================================\n\n/**\n * Centralized keyboard shortcut registry.\n *\n * Components register shortcuts via `register()` and receive a handle\n * to unregister when they unmount. The registry attaches a single global\n * keydown listener that dispatches to the highest-priority matching handler.\n *\n * @public\n */\nexport class KeyboardShortcutRegistry {\n private readonly _shortcuts: Map<string, IShortcut> = new Map();\n private _listener: ((e: KeyboardEvent) => void) | undefined;\n private _nextId: number = 0;\n\n /**\n * Registers a keyboard shortcut.\n * @param shortcut - The shortcut to register\n * @returns A registration handle with an `unregister()` method\n */\n public register(shortcut: IShortcut): IShortcutRegistration {\n const id = `ks-${++this._nextId}`;\n this._shortcuts.set(id, shortcut);\n this._ensureListener();\n\n return {\n unregister: (): void => {\n this._shortcuts.delete(id);\n if (this._shortcuts.size === 0) {\n this._removeListener();\n }\n }\n };\n }\n\n /**\n * Returns all currently registered shortcuts (for command palette / help display).\n */\n public getAll(): ReadonlyArray<IShortcut> {\n return Array.from(this._shortcuts.values());\n }\n\n /**\n * Dispatches a keyboard event to the highest-priority matching handler.\n * @param event - The keyboard event\n * @returns true if a handler consumed the event\n */\n public dispatch(event: KeyboardEvent): boolean {\n // Skip if the event target is an input/textarea/contenteditable\n const target = event.target as HTMLElement | null;\n if (target) {\n const tagName = target.tagName?.toLowerCase();\n if (tagName === 'input' || tagName === 'textarea' || target.isContentEditable) {\n return false;\n }\n }\n\n // Find all matching shortcuts, sorted by priority (highest first)\n const matches = Array.from(this._shortcuts.values())\n .filter((s) => matchesBinding(event, s.binding))\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n\n for (const shortcut of matches) {\n const result = shortcut.handler();\n if (result !== false) {\n event.preventDefault();\n event.stopPropagation();\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Removes all shortcuts and the global listener.\n */\n public dispose(): void {\n this._shortcuts.clear();\n this._removeListener();\n }\n\n private _ensureListener(): void {\n if (this._listener) {\n return;\n }\n this._listener = (e: KeyboardEvent): void => {\n this.dispatch(e);\n };\n document.addEventListener('keydown', this._listener);\n }\n\n private _removeListener(): void {\n if (this._listener) {\n document.removeEventListener('keydown', this._listener);\n this._listener = undefined;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKeyboardShortcuts.d.ts","sourceRoot":"","sources":["../../../src/packlets/keyboard/useKeyboardShortcuts.tsx"],"names":[],"mappings":"AAsBA;;;GAGG;AAEH,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,wBAAwB,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AActE;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,8BAA8B,GAAG,KAAK,CAAC,YAAY,CAQlG;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,wBAAwB,CAM9D;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,CAiC9E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKeyboardShortcuts.js","sourceRoot":"","sources":["../../../src/packlets/keyboard/useKeyboardShortcuts.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCH,4DAQC;AAWD,kDAMC;AAyBD,oDAiCC;AArHD;;;GAGG;AAEH,+CAAsE;AAEtE,yCAAsE;AAEtE,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,MAAM,eAAe,GAAwD,eAAK,CAAC,aAAa,CAE9F,SAAS,CAAC,CAAC;AAcb;;;;GAIG;AACH,SAAgB,wBAAwB,CAAC,KAAqC;IAC5E,MAAM,QAAQ,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,IAAI,mCAAwB,EAAE,EAAE,EAAE,CAAC,CAAC;IAEnE,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,OAAO,GAAS,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;IACxC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,OAAO,8BAAC,eAAe,CAAC,QAAQ,IAAC,KAAK,EAAE,QAAQ,IAAG,KAAK,CAAC,QAAQ,CAA4B,CAAC;AAChG,CAAC;AAED,+EAA+E;AAC/E,QAAQ;AACR,+EAA+E;AAE/E;;;;GAIG;AACH,SAAgB,mBAAmB;IACjC,MAAM,GAAG,GAAG,IAAA,kBAAU,EAAC,eAAe,CAAC,CAAC;IACxC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAgB,oBAAoB,CAAC,SAAmC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IACvC,MAAM,YAAY,GAAG,IAAA,cAAM,EAAC,SAAS,CAAC,CAAC;IACvC,YAAY,CAAC,OAAO,GAAG,SAAS,CAAC;IAEjC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,8EAA8E;QAC9E,6EAA6E;QAC7E,2EAA2E;QAC3E,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAC/D,QAAQ,CAAC,QAAQ,CAAC;YAChB,IAAI,OAAO;;gBACT,OAAO,MAAA,MAAA,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,0CAAE,OAAO,mCAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;YAC7D,CAAC;YACD,IAAI,WAAW;;gBACb,OAAO,MAAA,MAAA,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,0CAAE,WAAW,mCAAI,EAAE,CAAC;YACxD,CAAC;YACD,IAAI,QAAQ;;gBACV,OAAO,MAAA,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,0CAAE,QAAQ,CAAC;YAC/C,CAAC;YACD,OAAO,EAAE,GAAmB,EAAE;;gBAC5B,OAAO,MAAA,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,0CAAE,OAAO,EAAE,CAAC;YAChD,CAAC;SACF,CAAC,CACH,CAAC;QACF,OAAO,GAAS,EAAE;YAChB,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;gBAChC,GAAG,CAAC,UAAU,EAAE,CAAC;YACnB,CAAC;QACH,CAAC,CAAC;QACF,kFAAkF;QAClF,6EAA6E;IAC/E,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACnC,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * React context and hooks for the keyboard shortcut registry.\n * @packageDocumentation\n */\n\nimport React, { useContext, useEffect, useMemo, useRef } from 'react';\n\nimport { KeyboardShortcutRegistry, type IShortcut } from './registry';\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst KeyboardContext: React.Context<KeyboardShortcutRegistry | undefined> = React.createContext<\n KeyboardShortcutRegistry | undefined\n>(undefined);\n\n// ============================================================================\n// Provider\n// ============================================================================\n\n/**\n * Props for the KeyboardShortcutProvider.\n * @public\n */\nexport interface IKeyboardShortcutProviderProps {\n readonly children: React.ReactNode;\n}\n\n/**\n * Provides a KeyboardShortcutRegistry to the component tree.\n * Should be mounted once at the app root.\n * @public\n */\nexport function KeyboardShortcutProvider(props: IKeyboardShortcutProviderProps): React.ReactElement {\n const registry = useMemo(() => new KeyboardShortcutRegistry(), []);\n\n useEffect(() => {\n return (): void => registry.dispose();\n }, [registry]);\n\n return <KeyboardContext.Provider value={registry}>{props.children}</KeyboardContext.Provider>;\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Returns the keyboard shortcut registry.\n * Must be used within a KeyboardShortcutProvider.\n * @public\n */\nexport function useKeyboardRegistry(): KeyboardShortcutRegistry {\n const ctx = useContext(KeyboardContext);\n if (ctx === undefined) {\n throw new Error('useKeyboardRegistry must be used within a KeyboardShortcutProvider');\n }\n return ctx;\n}\n\n/**\n * Registers one or more keyboard shortcuts for the lifetime of the component.\n * Shortcuts are automatically unregistered on unmount.\n *\n * @example\n * ```tsx\n * useKeyboardShortcuts([\n * {\n * binding: { key: 'k', meta: true },\n * description: 'Open command palette',\n * handler: () => { setCommandPaletteOpen(true); }\n * },\n * {\n * binding: { key: 'z', meta: true },\n * description: 'Undo',\n * handler: () => { workspace.undo(); }\n * }\n * ]);\n * ```\n *\n * @param shortcuts - Array of shortcuts to register\n * @public\n */\nexport function useKeyboardShortcuts(shortcuts: ReadonlyArray<IShortcut>): void {\n const registry = useKeyboardRegistry();\n const shortcutsRef = useRef(shortcuts);\n shortcutsRef.current = shortcuts;\n\n useEffect(() => {\n // Register stable wrapper shortcuts that delegate to the current ref entries.\n // This means the effect only runs when the registry changes or the number of\n // shortcuts changes — not on every render when the array identity changes.\n const registrations = shortcutsRef.current.map((__item, index) =>\n registry.register({\n get binding() {\n return shortcutsRef.current[index]?.binding ?? { key: '' };\n },\n get description() {\n return shortcutsRef.current[index]?.description ?? '';\n },\n get priority() {\n return shortcutsRef.current[index]?.priority;\n },\n handler: (): boolean | void => {\n return shortcutsRef.current[index]?.handler();\n }\n })\n );\n return (): void => {\n for (const reg of registrations) {\n reg.unregister();\n }\n };\n // Re-register only when the registry instance or the number of shortcuts changes.\n // Handler/binding updates are picked up via the ref without re-registration.\n }, [registry, shortcuts.length]);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagesContext.d.ts","sourceRoot":"","sources":["../../../src/packlets/messages/MessagesContext.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAqD,MAAM,OAAO,CAAC;AAE1E,OAAO,EAAiB,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAMnF;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC3C,kCAAkC;IAClC,QAAQ,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,KAAK,QAAQ,CAAC;IACpG,4EAA4E;IAC5E,QAAQ,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,yBAAyB;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;CAChD;AAcD;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,sDAAsD;IACtD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,eAAe;IACf,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,sBAAsB,GAAG,KAAK,CAAC,YAAY,CA2ClF;AAMD;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,qBAAqB,CAMnD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagesContext.js","sourceRoot":"","sources":["../../../src/packlets/messages/MessagesContext.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDH,4CA2CC;AAWD,kCAMC;AAhHD,+CAA0E;AAE1E,mCAAmF;AAuBnF,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,MAAM,eAAe,GAAqD,eAAK,CAAC,aAAa,CAE3F,SAAS,CAAC,CAAC;AAiBb;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,KAA6B;IAC5D,MAAM,EAAE,WAAW,GAAG,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC9C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,IAAA,gBAAQ,EAAa,EAAE,CAAC,CAAC;IACzD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,IAAA,gBAAQ,EAAc,IAAI,GAAG,EAAE,CAAC,CAAC;IAEzE,MAAM,UAAU,GAAG,IAAA,mBAAW,EAC5B,CAAC,QAAyB,EAAE,IAAY,EAAE,MAAuB,EAAY,EAAE;QAC7E,MAAM,GAAG,GAAG,IAAA,qBAAa,EAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAClD,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE;YACnB,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;YAC5B,OAAO,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClF,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,CAAC;IACb,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;IAEF,MAAM,cAAc,GAAG,IAAA,mBAAW,EAAC,CAAC,EAAU,EAAQ,EAAE;QACtD,eAAe,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,aAAa,GAAG,IAAA,mBAAW,EAAC,GAAS,EAAE;QAC3C,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,eAAe,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAC7B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,YAAY,GAAG,IAAA,eAAO,EAC1B,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EACrD,CAAC,QAAQ,EAAE,YAAY,CAAC,CACzB,CAAC;IAEF,MAAM,KAAK,GAAG,IAAA,eAAO,EACnB,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ;QACR,UAAU;QACV,cAAc;QACd,aAAa;QACb,YAAY;KACb,CAAC,EACF,CAAC,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,CAAC,CACpE,CAAC;IAEF,OAAO,8BAAC,eAAe,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,IAAG,QAAQ,CAA4B,CAAC;AACvF,CAAC;AAED,+EAA+E;AAC/E,OAAO;AACP,+EAA+E;AAE/E;;;;GAIG;AACH,SAAgB,WAAW;IACzB,MAAM,GAAG,GAAG,IAAA,kBAAU,EAAC,eAAe,CAAC,CAAC;IACxC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport React, { useCallback, useContext, useMemo, useState } from 'react';\n\nimport { createMessage, IMessage, IMessageAction, MessageSeverity } from './model';\n\n// ============================================================================\n// Context Value\n// ============================================================================\n\n/**\n * Value provided by the MessagesContext.\n * @public\n */\nexport interface IMessagesContextValue {\n /** All messages in the stream (newest last) */\n readonly messages: ReadonlyArray<IMessage>;\n /** Add a message to the stream */\n readonly addMessage: (severity: MessageSeverity, text: string, action?: IMessageAction) => IMessage;\n /** Dismiss a specific message (removes from toast display, keeps in log) */\n readonly dismissMessage: (id: string) => void;\n /** Clear all messages */\n readonly clearMessages: () => void;\n /** Messages currently visible as toasts (not yet dismissed) */\n readonly activeToasts: ReadonlyArray<IMessage>;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst MessagesContext: React.Context<IMessagesContextValue | undefined> = React.createContext<\n IMessagesContextValue | undefined\n>(undefined);\n\n// ============================================================================\n// Provider\n// ============================================================================\n\n/**\n * Props for the MessagesProvider.\n * @public\n */\nexport interface IMessagesProviderProps {\n /** Maximum number of messages to retain in the log */\n readonly maxMessages?: number;\n /** Children */\n readonly children: React.ReactNode;\n}\n\n/**\n * Provides the global message stream to the component tree.\n * @public\n */\nexport function MessagesProvider(props: IMessagesProviderProps): React.ReactElement {\n const { maxMessages = 200, children } = props;\n const [messages, setMessages] = useState<IMessage[]>([]);\n const [dismissedIds, setDismissedIds] = useState<Set<string>>(new Set());\n\n const addMessage = useCallback(\n (severity: MessageSeverity, text: string, action?: IMessageAction): IMessage => {\n const msg = createMessage(severity, text, action);\n setMessages((prev) => {\n const next = [...prev, msg];\n return next.length > maxMessages ? next.slice(next.length - maxMessages) : next;\n });\n return msg;\n },\n [maxMessages]\n );\n\n const dismissMessage = useCallback((id: string): void => {\n setDismissedIds((prev) => new Set(prev).add(id));\n }, []);\n\n const clearMessages = useCallback((): void => {\n setMessages([]);\n setDismissedIds(new Set());\n }, []);\n\n const activeToasts = useMemo(\n () => messages.filter((m) => !dismissedIds.has(m.id)),\n [messages, dismissedIds]\n );\n\n const value = useMemo<IMessagesContextValue>(\n () => ({\n messages,\n addMessage,\n dismissMessage,\n clearMessages,\n activeToasts\n }),\n [messages, addMessage, dismissMessage, clearMessages, activeToasts]\n );\n\n return <MessagesContext.Provider value={value}>{children}</MessagesContext.Provider>;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook to access the messages context.\n * Must be used within a MessagesProvider.\n * @public\n */\nexport function useMessages(): IMessagesContextValue {\n const ctx = useContext(MessagesContext);\n if (ctx === undefined) {\n throw new Error('useMessages must be used within a MessagesProvider');\n }\n return ctx;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagesLogger.d.ts","sourceRoot":"","sources":["../../../src/packlets/messages/MessagesLogger.ts"],"names":[],"mappings":"AAsBA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,KAAK,eAAe,EAAE,OAAO,EAAW,MAAM,eAAe,CAAC;AAEhF,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AA8B/D;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAe,SAAQ,OAAO,CAAC,UAAU;IACpD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAE5D;;;;;OAKG;gBAED,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,EAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC,gBAAgB,EACnC,aAAa,CAAC,EAAE,cAAc;IAOhC;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAQrF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagesLogger.js","sourceRoot":"","sources":["../../../src/packlets/messages/MessagesLogger.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAEH;;;;;;;GAOG;AAEH,4CAAgF;AAKhF,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAE/E;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAAsB;IACzC,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAa,cAAe,SAAQ,kBAAO,CAAC,UAAU;IAIpD;;;;;OAKG;IACH,YACE,UAA+C,EAC/C,QAAmC,EACnC,aAA8B;QAE9B,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAC9B,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;IACtC,CAAC;IAED;;;;;;OAMG;IACO,IAAI,CAAC,OAAe,EAAE,KAAsB;QACpD,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;YACzD,OAAO,IAAA,kBAAO,EAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,IAAA,kBAAO,EAAC,SAAS,CAAC,CAAC;IAC5B,CAAC;CACF;AAnCD,wCAmCC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Bridge between the MessagesContext and the ts-utils ILogger/LogReporter system.\n *\n * Provides an ILogger implementation that routes log messages into the\n * MessagesContext, enabling Result.report() integration in React components.\n *\n * @packageDocumentation\n */\n\nimport { Logging, type MessageLogLevel, Success, succeed } from '@fgv/ts-utils';\n\nimport { type IMessageAction, type MessageSeverity } from './model';\nimport { type IMessagesContextValue } from './MessagesContext';\n\n// ============================================================================\n// Level Mapping\n// ============================================================================\n\n/**\n * Maps ts-utils MessageLogLevel to our MessageSeverity.\n * `detail` maps to `'info'` (shown when logLevel is 'detail' or 'all').\n * `quiet` is always suppressed (only shown when reporter level is 'all', handled upstream).\n * @internal\n */\nfunction mapLogLevel(level: MessageLogLevel): MessageSeverity | undefined {\n switch (level) {\n case 'detail':\n case 'info':\n return 'info';\n case 'warning':\n return 'warning';\n case 'error':\n return 'error';\n case 'quiet':\n return undefined;\n }\n}\n\n// ============================================================================\n// MessagesLogger\n// ============================================================================\n\n/**\n * An {@link @fgv/ts-utils#Logging.ILogger | ILogger} implementation that routes\n * messages into a {@link IMessagesContextValue | MessagesContext}.\n *\n * Use this as the `logger` parameter when creating a `LogReporter` to get\n * full `Result.report()` integration that feeds into the app's toast/log system.\n *\n * @example\n * ```typescript\n * const { addMessage } = useMessages();\n * const logger = new MessagesLogger(addMessage);\n * const reporter = new LogReporter<unknown>({ logger });\n *\n * // Now Result.report() flows into toasts + log panel\n * someResult.report(reporter, { success: 'info', failure: 'error' });\n * ```\n *\n * @public\n */\nexport class MessagesLogger extends Logging.LoggerBase {\n private readonly _addMessage: IMessagesContextValue['addMessage'];\n private readonly _defaultAction: IMessageAction | undefined;\n\n /**\n * Creates a new MessagesLogger.\n * @param addMessage - The addMessage function from MessagesContext\n * @param logLevel - The minimum log level to display (default: 'info')\n * @param defaultAction - Optional default action to attach to all messages\n */\n public constructor(\n addMessage: IMessagesContextValue['addMessage'],\n logLevel?: Logging.ReporterLogLevel,\n defaultAction?: IMessageAction\n ) {\n super(logLevel);\n this._addMessage = addMessage;\n this._defaultAction = defaultAction;\n }\n\n /**\n * Routes a formatted log message into the MessagesContext.\n * @param message - The formatted message string\n * @param level - The log level\n * @returns Success with the message if it was logged, or Success with undefined if suppressed\n * @internal\n */\n protected _log(message: string, level: MessageLogLevel): Success<string | undefined> {\n const severity = mapLogLevel(level);\n if (severity !== undefined) {\n this._addMessage(severity, message, this._defaultAction);\n return succeed(message);\n }\n return succeed(undefined);\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusBar.d.ts","sourceRoot":"","sources":["../../../src/packlets/messages/StatusBar.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,EAAE,OAAO,EAAwB,MAAM,eAAe,CAAC;AAI9D,OAAO,EAAE,QAAQ,EAAmB,MAAM,SAAS,CAAC;AAsDpD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,iEAAiE;IACjE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;CACxD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,eAAe,GAAG,KAAK,CAAC,YAAY,CA2MpE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusBar.js","sourceRoot":"","sources":["../../../src/packlets/messages/StatusBar.tsx"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport { Logging, type MessageLogLevel } from '@fgv/ts-utils';\nimport { FunnelIcon, DocumentDuplicateIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline';\nimport { CheckIcon } from '@heroicons/react/24/solid';\n\nimport { IMessage, MessageSeverity } from './model';\nimport { useResponsive } from '../responsive';\n\n// ============================================================================\n// Severity display config\n// ============================================================================\n\nconst SEVERITY_ICONS: Record<MessageSeverity, string> = {\n info: '\\u2139',\n success: '\\u2713',\n warning: '\\u26A0',\n error: '\\u2717'\n};\n\nconst SEVERITY_COLORS: Record<MessageSeverity, string> = {\n info: 'text-status-info-icon',\n success: 'text-status-success-icon',\n warning: 'text-status-warning-icon',\n error: 'text-status-error-icon'\n};\n\nconst LOG_ROW_COLORS: Record<MessageSeverity, string> = {\n info: '',\n success: 'bg-status-success-bg',\n warning: 'bg-status-warning-bg',\n error: 'bg-status-error-bg'\n};\n\n// ============================================================================\n// Level filter config\n// ============================================================================\n\n/**\n * Maps MessageSeverity to MessageLogLevel for shouldLog filtering.\n * 'success' is treated as 'info' since it doesn't exist in the log level hierarchy.\n */\nfunction severityToLogLevel(severity: MessageSeverity): MessageLogLevel {\n return severity === 'success' ? 'info' : severity;\n}\n\n/**\n * Filter choices exposed in the UI, mapping labels to ReporterLogLevel values.\n */\nconst FILTER_LEVELS: ReadonlyArray<{ readonly label: string; readonly level: Logging.ReporterLogLevel }> = [\n { label: 'All', level: 'all' },\n { label: 'Info+', level: 'info' },\n { label: 'Warn+', level: 'warning' },\n { label: 'Error', level: 'error' }\n] as const;\n\n// ============================================================================\n// Status Bar\n// ============================================================================\n\n/**\n * Props for the StatusBar component.\n * @public\n */\nexport interface IStatusBarProps {\n readonly messages: ReadonlyArray<IMessage>;\n readonly onClear: () => void;\n /** Initial filter level for the log panel. Defaults to 'all'. */\n readonly initialFilterLevel?: Logging.ReporterLogLevel;\n}\n\n/**\n * Collapsible status bar / log panel at the bottom of the application.\n *\n * Collapsed: shows severity counts.\n * Expanded: filterable, searchable, copyable log of all messages.\n * @public\n */\nexport function StatusBar(props: IStatusBarProps): React.ReactElement {\n const { messages, onClear, initialFilterLevel } = props;\n const { layoutMode } = useResponsive();\n const isMobile = layoutMode === 'mobile';\n const [expanded, setExpanded] = useState(false);\n const [showFilters, setShowFilters] = useState(false);\n const [filterLevel, setFilterLevel] = useState<Logging.ReporterLogLevel>(initialFilterLevel ?? 'all');\n const [searchTerm, setSearchTerm] = useState('');\n const [copySuccessId, setCopySuccessId] = useState<string | null>(null);\n\n const counts = useMemo(() => {\n const result: Record<MessageSeverity, number> = { info: 0, success: 0, warning: 0, error: 0 };\n for (const msg of messages) {\n result[msg.severity]++;\n }\n return result;\n }, [messages]);\n\n const filteredMessages = useMemo(() => {\n return messages.filter((msg) => {\n const passesLevel = Logging.shouldLog(severityToLogLevel(msg.severity), filterLevel);\n const passesSearch = searchTerm === '' || msg.text.toLowerCase().includes(searchTerm.toLowerCase());\n return passesLevel && passesSearch;\n });\n }, [messages, filterLevel, searchTerm]);\n\n const isFiltered = filteredMessages.length !== messages.length;\n\n const formatTime = useCallback((timestamp: number): string => {\n return new Date(timestamp).toLocaleTimeString();\n }, []);\n\n const copyToClipboard = useCallback((text: string, id: string): void => {\n navigator.clipboard\n .writeText(text)\n .then(() => {\n setCopySuccessId(id);\n setTimeout(() => setCopySuccessId(null), 2000);\n })\n .catch(() => undefined);\n }, []);\n\n const copyAllFiltered = useCallback((): void => {\n const text = filteredMessages\n .map((msg) => `[${msg.severity.toUpperCase()}] ${formatTime(msg.timestamp)} - ${msg.text}`)\n .join('\\n');\n copyToClipboard(text, '__all__');\n }, [filteredMessages, formatTime, copyToClipboard]);\n\n return (\n <div className=\"border-t border-border bg-surface\">\n {/* Collapsed bar */}\n <button\n onClick={(): void => setExpanded(!expanded)}\n className=\"flex items-center justify-between w-full px-4 py-1.5 text-xs text-secondary hover:bg-hover\"\n >\n <div className=\"flex items-center gap-4\">\n {(Object.keys(counts) as MessageSeverity[]).map((severity) =>\n counts[severity] > 0 ? (\n <span key={severity} className={`flex items-center gap-1 ${SEVERITY_COLORS[severity]}`}>\n <span>{SEVERITY_ICONS[severity]}</span>\n <span>{counts[severity]}</span>\n </span>\n ) : null\n )}\n {messages.length === 0 && <span className=\"text-muted\">No messages</span>}\n </div>\n <span className=\"text-muted\">{expanded ? '\\u25BC' : '\\u25B2'}</span>\n </button>\n\n {/* Expanded log — fixed slide-up sheet on mobile, inline on desktop */}\n {expanded && (\n <>\n {isMobile && (\n <div className=\"fixed inset-0 z-40 bg-backdrop\" onClick={(): void => setExpanded(false)} />\n )}\n <div\n className={\n isMobile\n ? 'fixed inset-x-0 bottom-8 z-50 flex flex-col bg-surface border-t border-border shadow-xl rounded-t-lg max-h-[70vh]'\n : 'border-t border-border-subtle'\n }\n >\n {/* Header toolbar */}\n <div className=\"flex items-center justify-between px-4 py-1 bg-surface-alt border-b border-border-subtle shrink-0\">\n <span className=\"text-xs font-medium text-muted\">\n {isFiltered\n ? `${filteredMessages.length} of ${messages.length} messages`\n : `${messages.length} message${messages.length !== 1 ? 's' : ''}`}\n </span>\n <div className=\"flex items-center gap-1\">\n <button\n onClick={(): void => setShowFilters(!showFilters)}\n className={`p-1 rounded hover:bg-surface-raised ${showFilters ? 'bg-surface-raised' : ''}`}\n title=\"Filter messages\"\n >\n <FunnelIcon className=\"h-3.5 w-3.5 text-muted\" />\n </button>\n <button\n onClick={copyAllFiltered}\n className={`p-1 rounded transition-colors ${\n copySuccessId === '__all__' ? 'bg-status-success-bg' : 'hover:bg-surface-raised'\n }`}\n title={copySuccessId === '__all__' ? 'Copied!' : 'Copy filtered messages'}\n >\n {copySuccessId === '__all__' ? (\n <CheckIcon className=\"h-3.5 w-3.5 text-status-success-icon\" />\n ) : (\n <DocumentDuplicateIcon className=\"h-3.5 w-3.5 text-muted\" />\n )}\n </button>\n <button onClick={onClear} className=\"text-xs text-muted hover:text-secondary ml-1\">\n Clear\n </button>\n </div>\n </div>\n\n {/* Filter toolbar */}\n {showFilters && (\n <div className=\"px-4 py-1.5 bg-surface-raised border-b border-border-subtle flex items-center gap-3 shrink-0\">\n {/* Level filter buttons */}\n <div className=\"flex items-center gap-1\">\n {FILTER_LEVELS.map(({ label, level }) => (\n <button\n key={level}\n onClick={(): void => setFilterLevel(level)}\n className={`text-xs px-2 py-0.5 rounded border ${\n filterLevel === level\n ? 'bg-status-info-bg border-status-info-border text-status-info-text'\n : 'bg-surface border-border text-secondary hover:bg-hover'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n\n {/* Search input */}\n <div className=\"relative flex-1\">\n <MagnifyingGlassIcon className=\"absolute left-2 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted\" />\n <input\n type=\"text\"\n placeholder=\"Search messages...\"\n value={searchTerm}\n onChange={(e): void => setSearchTerm(e.target.value)}\n className=\"w-full pl-7 pr-6 py-0.5 text-xs border border-border rounded bg-surface text-primary focus:outline-none focus:ring-1 focus:ring-focus-ring focus:border-focus-ring\"\n />\n {searchTerm.length > 0 && (\n <button\n onClick={(): void => setSearchTerm('')}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 text-muted hover:text-secondary text-xs\"\n aria-label=\"Clear search\"\n >\n ×\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Message list */}\n <div className={`overflow-y-auto ${isMobile ? 'flex-1' : 'max-h-48'}`}>\n {filteredMessages.length === 0 ? (\n <div className=\"px-4 py-3 text-xs text-muted text-center\">\n {isFiltered ? 'No messages match the current filter' : 'No messages'}\n </div>\n ) : (\n filteredMessages.map((msg) => (\n <div\n key={msg.id}\n className={`group flex items-start gap-2 px-4 py-1.5 text-xs border-b border-border-subtle ${\n LOG_ROW_COLORS[msg.severity]\n }`}\n >\n <span className={`shrink-0 ${SEVERITY_COLORS[msg.severity]}`}>\n {SEVERITY_ICONS[msg.severity]}\n </span>\n <span className=\"flex-1 text-secondary\">{msg.text}</span>\n <button\n onClick={(): void => copyToClipboard(msg.text, msg.id)}\n className={`shrink-0 p-0.5 rounded transition-colors ${\n copySuccessId === msg.id\n ? 'opacity-100 bg-status-success-surface'\n : 'opacity-0 group-hover:opacity-100 hover:bg-surface-raised'\n }`}\n title={copySuccessId === msg.id ? 'Copied!' : 'Copy message'}\n >\n {copySuccessId === msg.id ? (\n <CheckIcon className=\"h-3 w-3 text-status-success-icon\" />\n ) : (\n <DocumentDuplicateIcon className=\"h-3 w-3 text-muted\" />\n )}\n </button>\n <span className=\"shrink-0 text-muted\">{formatTime(msg.timestamp)}</span>\n </div>\n ))\n )}\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../src/packlets/messages/Toast.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAEzC,OAAO,EAAwB,QAAQ,EAAmB,MAAM,SAAS,CAAC;AAkB1E;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,eAAe,GAAG,KAAK,CAAC,YAAY,CA0CpE;AAMD;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,sDAAsD;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAoBrF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.js","sourceRoot":"","sources":["../../../src/packlets/messages/Toast.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCH,8BA0CC;AAqBD,wCAoBC;AApHD,+CAAyC;AAEzC,mCAA0E;AAC1E,8CAA8C;AAE9C,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E,MAAM,eAAe,GAAoC;IACvD,IAAI,EAAE,mEAAmE;IACzE,OAAO,EAAE,4EAA4E;IACrF,OAAO,EAAE,4EAA4E;IACrF,KAAK,EAAE,sEAAsE;CAC9E,CAAC;AAeF;;;GAGG;AACH,SAAgB,SAAS,CAAC,KAAsB;IAC9C,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACrC,MAAM,MAAM,GAAG,4BAAoB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,EAAE,UAAU,EAAE,GAAG,IAAA,0BAAa,GAAE,CAAC;IAEvC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,MAAM,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;YAC5E,OAAO,GAAS,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;IAElD,OAAO,CACL,uCACE,SAAS,EAAE,gEACT,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UACvC,IAAI,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EACvC,IAAI,EAAC,OAAO;QAEZ,uCAAK,SAAS,EAAC,6BAA6B,EAAC,KAAK,EAAE,OAAO,CAAC,IAAI,IAC7D,OAAO,CAAC,IAAI,CACT;QACN,uCAAK,SAAS,EAAC,kCAAkC;YAC9C,OAAO,CAAC,MAAM,IAAI,CACjB,0CACE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAChC,SAAS,EAAC,kDAAkD,IAE3D,OAAO,CAAC,MAAM,CAAC,KAAK,CACd,CACV;YACD,0CACE,OAAO,EAAE,GAAS,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAC1C,SAAS,EAAC,2CAA2C,gBAC1C,SAAS,aAGb,CACL,CACF,CACP,CAAC;AACJ,CAAC;AAiBD;;;GAGG;AACH,SAAgB,cAAc,CAAC,KAA2B;IACxD,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC;IACpD,MAAM,EAAE,UAAU,EAAE,GAAG,IAAA,0BAAa,GAAE,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;IAE1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,uCACE,SAAS,EAAE,4CACT,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAC/C,EAAE,IAED,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACtB,8BAAC,SAAS,IAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAI,CACnE,CAAC,CACE,CACP,CAAC;AACJ,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport React, { useEffect } from 'react';\n\nimport { DEFAULT_TOAST_CONFIG, IMessage, MessageSeverity } from './model';\nimport { useResponsive } from '../responsive';\n\n// ============================================================================\n// Severity Styles\n// ============================================================================\n\nconst SEVERITY_STYLES: Record<MessageSeverity, string> = {\n info: 'bg-status-info-bg border-status-info-border text-status-info-text',\n success: 'bg-status-success-bg border-status-success-border text-status-success-text',\n warning: 'bg-status-warning-bg border-status-warning-border text-status-warning-text',\n error: 'bg-status-error-bg border-status-error-border text-status-error-text'\n};\n\n// ============================================================================\n// Single Toast\n// ============================================================================\n\n/**\n * Props for a single Toast item.\n * @public\n */\nexport interface IToastItemProps {\n readonly message: IMessage;\n readonly onDismiss: (id: string) => void;\n}\n\n/**\n * A single toast notification.\n * @public\n */\nexport function ToastItem(props: IToastItemProps): React.ReactElement {\n const { message, onDismiss } = props;\n const config = DEFAULT_TOAST_CONFIG[message.severity];\n const { layoutMode } = useResponsive();\n\n useEffect(() => {\n if (config.autoDismissMs > 0) {\n const timer = setTimeout(() => onDismiss(message.id), config.autoDismissMs);\n return (): void => clearTimeout(timer);\n }\n return undefined;\n }, [message.id, config.autoDismissMs, onDismiss]);\n\n return (\n <div\n className={`flex items-start gap-3 px-4 py-3 rounded-lg border shadow-lg ${\n layoutMode === 'mobile' ? 'w-full' : 'max-w-sm'\n } ${SEVERITY_STYLES[message.severity]}`}\n role=\"alert\"\n >\n <div className=\"flex-1 text-sm line-clamp-4\" title={message.text}>\n {message.text}\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {message.action && (\n <button\n onClick={message.action.onAction}\n className=\"text-sm font-medium underline hover:no-underline\"\n >\n {message.action.label}\n </button>\n )}\n <button\n onClick={(): void => onDismiss(message.id)}\n className=\"text-current opacity-50 hover:opacity-100\"\n aria-label=\"Dismiss\"\n >\n ×\n </button>\n </div>\n </div>\n );\n}\n\n// ============================================================================\n// Toast Container\n// ============================================================================\n\n/**\n * Props for the ToastContainer.\n * @public\n */\nexport interface IToastContainerProps {\n readonly toasts: ReadonlyArray<IMessage>;\n readonly onDismiss: (id: string) => void;\n /** Maximum number of toasts to show simultaneously */\n readonly maxVisible?: number;\n}\n\n/**\n * Container that renders active toasts in the bottom-right corner.\n * @public\n */\nexport function ToastContainer(props: IToastContainerProps): React.ReactElement | null {\n const { toasts, onDismiss, maxVisible = 5 } = props;\n const { layoutMode } = useResponsive();\n const visible = toasts.slice(-maxVisible);\n\n if (visible.length === 0) {\n return null;\n }\n\n return (\n <div\n className={`fixed bottom-16 z-50 flex flex-col gap-2 ${\n layoutMode === 'mobile' ? 'left-4 right-4' : 'right-4'\n }`}\n >\n {visible.map((toast) => (\n <ToastItem key={toast.id} message={toast} onDismiss={onDismiss} />\n ))}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/messages/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAErG,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/messages/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,iCAQiB;AAHf,6GAAA,oBAAoB,OAAA;AACpB,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AAGnB,qDAK2B;AAFzB,mHAAA,gBAAgB,OAAA;AAChB,8GAAA,WAAW,OAAA;AAGb,iCAAqG;AAA5F,kGAAA,SAAS,OAAA;AAAE,uGAAA,cAAc,OAAA;AAElC,yCAA8D;AAArD,sGAAA,SAAS,OAAA;AAElB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AAEvB,mDAA+E;AAAtE,gHAAA,cAAc,OAAA","sourcesContent":["/**\n * Messages packlet - observability context, toast system, and log panel.\n * @packageDocumentation\n */\n\nexport {\n type MessageSeverity,\n type IMessage,\n type IMessageAction,\n type IToastConfig,\n DEFAULT_TOAST_CONFIG,\n createMessage,\n generateMessageId\n} from './model';\n\nexport {\n type IMessagesContextValue,\n type IMessagesProviderProps,\n MessagesProvider,\n useMessages\n} from './MessagesContext';\n\nexport { ToastItem, ToastContainer, type IToastItemProps, type IToastContainerProps } from './Toast';\n\nexport { StatusBar, type IStatusBarProps } from './StatusBar';\n\nexport { MessagesLogger } from './MessagesLogger';\n\nexport { useLogReporter, type IUseLogReporterOptions } from './useLogReporter';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/packlets/messages/model.ts"],"names":[],"mappings":"AAsBA;;;GAGG;AAMH;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAMvE;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,wBAAwB;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uBAAuB;IACvB,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,mBAAmB;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,mBAAmB;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC/B;AAMD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,eAAe,EAAE,YAAY,CAK7D,CAAC;AAQX;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,QAAQ,CAQxG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/packlets/messages/model.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAmFH,8CAEC;AAMD,sCAQC;AArCD;;;GAGG;AACU,QAAA,oBAAoB,GAA0C;IACzE,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;IAC7B,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;IAChC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;IAChC,KAAK,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE;CACnB,CAAC;AAEX,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,IAAI,OAAO,GAAW,CAAC,CAAC;AAExB;;;GAGG;AACH,SAAgB,iBAAiB;IAC/B,OAAO,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa,CAAC,QAAyB,EAAE,IAAY,EAAE,MAAuB;IAC5F,OAAO;QACL,EAAE,EAAE,iBAAiB,EAAE;QACvB,QAAQ;QACR,IAAI;QACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,MAAM;KACP,CAAC;AACJ,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Message model types for the observability system.\n * @packageDocumentation\n */\n\n// ============================================================================\n// Message Severity\n// ============================================================================\n\n/**\n * Severity levels for messages.\n * @public\n */\nexport type MessageSeverity = 'info' | 'success' | 'warning' | 'error';\n\n// ============================================================================\n// Message\n// ============================================================================\n\n/**\n * A single message in the observability stream.\n * @public\n */\nexport interface IMessage {\n /** Unique message ID */\n readonly id: string;\n /** Message severity */\n readonly severity: MessageSeverity;\n /** Message text */\n readonly text: string;\n /** Timestamp (ms since epoch) */\n readonly timestamp: number;\n /** Optional action (e.g., a link or callback) */\n readonly action?: IMessageAction;\n}\n\n/**\n * An actionable element attached to a message (e.g., \"Go to Session\" link).\n * @public\n */\nexport interface IMessageAction {\n /** Action label */\n readonly label: string;\n /** Callback when the action is triggered */\n readonly onAction: () => void;\n}\n\n// ============================================================================\n// Toast Configuration\n// ============================================================================\n\n/**\n * Configuration for toast auto-dismiss behavior.\n * @public\n */\nexport interface IToastConfig {\n /** Auto-dismiss duration in ms. 0 = no auto-dismiss. */\n readonly autoDismissMs: number;\n}\n\n/**\n * Default toast configuration by severity.\n * @public\n */\nexport const DEFAULT_TOAST_CONFIG: Record<MessageSeverity, IToastConfig> = {\n info: { autoDismissMs: 3000 },\n success: { autoDismissMs: 3000 },\n warning: { autoDismissMs: 5000 },\n error: { autoDismissMs: 0 }\n} as const;\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nlet _nextId: number = 0;\n\n/**\n * Generates a unique message ID.\n * @internal\n */\nexport function generateMessageId(): string {\n return `msg-${++_nextId}-${Date.now().toString(36)}`;\n}\n\n/**\n * Creates a new message.\n * @public\n */\nexport function createMessage(severity: MessageSeverity, text: string, action?: IMessageAction): IMessage {\n return {\n id: generateMessageId(),\n severity,\n text,\n timestamp: Date.now(),\n action\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLogReporter.d.ts","sourceRoot":"","sources":["../../../src/packlets/messages/useLogReporter.ts"],"names":[],"mappings":"AA8CA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAKxC;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;CAC9C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAQ7F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLogReporter.js","sourceRoot":"","sources":["../../../src/packlets/messages/useLogReporter.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AAmDH,wCAQC;AAzDD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,iCAAgC;AAEhC,4CAAwC;AAExC,uDAAgD;AAChD,qDAAkD;AAWlD;;;;;;;;;;GAUG;AACH,SAAgB,cAAc,CAAC,OAAgC;IAC7D,MAAM,EAAE,UAAU,EAAE,GAAG,IAAA,6BAAW,GAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,CAAC;IAEnC,OAAO,IAAA,eAAO,EAAC,GAAG,EAAE;QAClB,MAAM,MAAM,GAAG,IAAI,+BAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACxD,OAAO,IAAI,kBAAO,CAAC,WAAW,CAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC7B,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * React hook that provides a LogReporter wired into the MessagesContext.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const reporter = useLogReporter();\n *\n * const handleSave = () => {\n * const result = workspace.save(data);\n * // Automatically shows success toast or error in log panel\n * result.report(reporter, {\n * success: { level: 'info', message: () => 'Saved successfully' },\n * failure: 'error'\n * });\n * };\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { useMemo } from 'react';\n\nimport { Logging } from '@fgv/ts-utils';\n\nimport { useMessages } from './MessagesContext';\nimport { MessagesLogger } from './MessagesLogger';\n\n/**\n * Options for the useLogReporter hook.\n * @public\n */\nexport interface IUseLogReporterOptions {\n /** Minimum log level (default: 'info') */\n readonly logLevel?: Logging.ReporterLogLevel;\n}\n\n/**\n * React hook that creates a {@link @fgv/ts-utils#Logging.LogReporter | LogReporter}\n * backed by the MessagesContext.\n *\n * The returned reporter implements both `ILogger` and `IResultReporter<unknown>`,\n * so it can be used with `Result.report()` and direct logging calls.\n *\n * @param options - Optional configuration\n * @returns A LogReporter that routes messages into the toast/log system\n * @public\n */\nexport function useLogReporter(options?: IUseLogReporterOptions): Logging.LogReporter<unknown> {\n const { addMessage } = useMessages();\n const logLevel = options?.logLevel;\n\n return useMemo(() => {\n const logger = new MessagesLogger(addMessage, logLevel);\n return new Logging.LogReporter<unknown>({ logger });\n }, [addMessage, logLevel]);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.d.ts","sourceRoot":"","sources":["../../../src/packlets/modal/ConfirmDialog.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAiC,MAAM,OAAO,CAAC;AAGtD;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,mBAAmB;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC,2DAA2D;IAC3D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,yDAAyD;IACzD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IAC1C,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC/B;AAcD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAoHnF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.js","sourceRoot":"","sources":["../../../src/packlets/modal/ConfirmDialog.tsx"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport React, { useCallback, useEffect } from 'react';\nimport { useResponsive } from '../responsive';\n\n/**\n * Severity level for the confirm dialog.\n * Controls the color of the confirm button.\n * @public\n */\nexport type ConfirmDialogSeverity = 'danger' | 'warning' | 'info';\n\n/**\n * Props for the ConfirmDialog component.\n * @public\n */\nexport interface IConfirmDialogProps {\n /** Whether the dialog is open */\n readonly isOpen: boolean;\n /** Dialog title */\n readonly title: string;\n /** Dialog message body */\n readonly message: React.ReactNode;\n /** Label for the confirm button (defaults to 'Confirm') */\n readonly confirmLabel?: string;\n /** Label for the cancel button (defaults to 'Cancel') */\n readonly cancelLabel?: string;\n /** Severity level controlling confirm button color (defaults to 'danger') */\n readonly severity?: ConfirmDialogSeverity;\n /** Called when the user confirms */\n readonly onConfirm: () => void;\n /** Called when the user cancels or closes */\n readonly onCancel: () => void;\n}\n\nconst severityClasses: Record<ConfirmDialogSeverity, string> = {\n danger: 'bg-status-error-btn hover:bg-status-error-btn-hover focus:ring-status-error-accent',\n warning: 'bg-status-warning-btn hover:bg-status-warning-btn-hover focus:ring-status-warning-strong',\n info: 'bg-status-info-btn hover:bg-status-info-btn-hover focus:ring-status-info-icon'\n};\n\nconst severityIconClasses: Record<ConfirmDialogSeverity, string> = {\n danger: 'text-status-error-icon',\n warning: 'text-status-warning-icon',\n info: 'text-status-info-icon'\n};\n\n/**\n * Generic confirmation dialog.\n *\n * Renders a modal overlay with a title, message, and confirm/cancel buttons.\n * Closes on Escape key or backdrop click (treated as cancel).\n *\n * @public\n */\nexport function ConfirmDialog(props: IConfirmDialogProps): React.ReactElement | null {\n const {\n isOpen,\n title,\n message,\n confirmLabel = 'Confirm',\n cancelLabel = 'Cancel',\n severity = 'danger',\n onConfirm,\n onCancel\n } = props;\n const { layoutMode } = useResponsive();\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n onCancel();\n }\n },\n [onCancel]\n );\n\n useEffect(() => {\n if (isOpen) {\n document.addEventListener('keydown', handleKeyDown);\n return (): void => document.removeEventListener('keydown', handleKeyDown);\n }\n return undefined;\n }, [isOpen, handleKeyDown]);\n\n if (!isOpen) {\n return null;\n }\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-backdrop\" onClick={onCancel} role=\"presentation\" />\n\n {/* Dialog */}\n <div\n className={`relative bg-surface rounded-lg shadow-xl ${\n layoutMode === 'mobile' ? 'w-[95vw]' : 'max-w-md w-full mx-4'\n }`}\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby=\"confirm-dialog-title\"\n aria-describedby=\"confirm-dialog-message\"\n >\n <div className=\"p-6\">\n <div className=\"flex items-start gap-4\">\n {/* Icon */}\n <div\n className={`flex-shrink-0 w-10 h-10 flex items-center justify-center rounded-full ${\n severity === 'danger'\n ? 'bg-status-error-bg'\n : severity === 'warning'\n ? 'bg-status-warning-bg'\n : 'bg-status-info-bg'\n }`}\n >\n <svg\n className={`w-6 h-6 ${severityIconClasses[severity]}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n {severity === 'info' ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n )}\n </svg>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 min-w-0\">\n <h3 id=\"confirm-dialog-title\" className=\"text-base font-semibold text-primary leading-6\">\n {title}\n </h3>\n <div id=\"confirm-dialog-message\" className=\"mt-2 text-sm text-secondary\">\n {typeof message === 'string' ? <p>{message}</p> : message}\n </div>\n </div>\n </div>\n\n {/* Buttons */}\n <div className=\"mt-6 flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-secondary bg-surface border border-border rounded-md hover:bg-hover focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-focus-ring transition-colors\"\n >\n {cancelLabel}\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n className={`px-4 py-2 text-sm font-medium text-white rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors ${severityClasses[severity]}`}\n >\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../../src/packlets/modal/Modal.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAiC,MAAM,OAAO,CAAC;AAGtD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,kCAAkC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,kBAAkB;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAwDnE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../../src/packlets/modal/Modal.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBH,sBAwDC;AA/ED,+CAAsD;AACtD,8CAA8C;AAiB9C;;;;GAIG;AACH,SAAgB,KAAK,CAAC,KAAkB;IACtC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACnD,MAAM,EAAE,UAAU,EAAE,GAAG,IAAA,0BAAa,GAAE,CAAC;IAEvC,MAAM,aAAa,GAAG,IAAA,mBAAW,EAC/B,CAAC,CAAgB,EAAQ,EAAE;QACzB,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,MAAM,EAAE,CAAC;YACX,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;YACpD,OAAO,GAAS,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IAE5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,uCAAK,SAAS,EAAC,qDAAqD;QAElE,uCAAK,SAAS,EAAC,8BAA8B,EAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAC,cAAc,GAAG;QAGtF,uCACE,SAAS,EAAE,0DACT,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,mCACtD,EAAE,EACF,IAAI,EAAC,QAAQ,gBACF,MAAM,gBACL,KAAK;YAGjB,uCAAK,SAAS,EAAC,oEAAoE;gBACjF,sCAAI,SAAS,EAAC,oCAAoC,IAAE,KAAK,CAAM;gBAC/D,0CACE,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,mDAAmD,gBAClD,OAAO,aAGX,CACL;YAGN,uCAAK,SAAS,EAAC,kCAAkC,IAAE,QAAQ,CAAO,CAC9D,CACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport React, { useCallback, useEffect } from 'react';\nimport { useResponsive } from '../responsive';\n\n/**\n * Props for the Modal component.\n * @public\n */\nexport interface IModalProps {\n /** Whether the modal is open */\n readonly isOpen: boolean;\n /** Callback to close the modal */\n readonly onClose: () => void;\n /** Modal title */\n readonly title: string;\n /** Modal content */\n readonly children: React.ReactNode;\n}\n\n/**\n * Generic modal overlay component.\n * Renders a centered dialog with a backdrop that closes on click or Escape.\n * @public\n */\nexport function Modal(props: IModalProps): React.ReactElement | null {\n const { isOpen, onClose, title, children } = props;\n const { layoutMode } = useResponsive();\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n onClose();\n }\n },\n [onClose]\n );\n\n useEffect(() => {\n if (isOpen) {\n document.addEventListener('keydown', handleKeyDown);\n return (): void => document.removeEventListener('keydown', handleKeyDown);\n }\n return undefined;\n }, [isOpen, handleKeyDown]);\n\n if (!isOpen) {\n return null;\n }\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-backdrop\" onClick={onClose} role=\"presentation\" />\n\n {/* Dialog */}\n <div\n className={`relative bg-surface rounded-lg shadow-xl flex flex-col ${\n layoutMode === 'mobile' ? 'w-[95vw] max-h-[95vh]' : 'max-w-lg w-full mx-4 max-h-[80vh]'\n }`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border\">\n <h2 className=\"text-lg font-semibold text-primary\">{title}</h2>\n <button\n onClick={onClose}\n className=\"text-muted hover:text-secondary transition-colors\"\n aria-label=\"Close\"\n >\n ×\n </button>\n </div>\n\n {/* Content */}\n <div className=\"px-6 py-4 overflow-y-auto flex-1\">{children}</div>\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/modal/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/modal/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,iCAAkD;AAAzC,8FAAA,KAAK,OAAA;AAEd,iDAAsG;AAA7F,8GAAA,aAAa,OAAA","sourcesContent":["/**\n * Modal packlet - generic overlay dialog component.\n * @packageDocumentation\n */\n\nexport { Modal, type IModalProps } from './Modal';\n\nexport { ConfirmDialog, type IConfirmDialogProps, type ConfirmDialogSeverity } from './ConfirmDialog';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrintEnclosure.d.ts","sourceRoot":"","sources":["../../../src/packlets/print/PrintEnclosure.tsx"],"names":[],"mappings":"AAsBA;;;GAGG;AAEH,OAAO,KAAsB,MAAM,OAAO,CAAC;AAG3C;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzC,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,aAAa,EACb,WAAW,EACX,QAAQ,EACT,EAAE,oBAAoB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAuC1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrintEnclosure.js","sourceRoot":"","sources":["../../../src/packlets/print/PrintEnclosure.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCH,wCA4CC;AA/ED;;;GAGG;AAEH,+CAA2C;AAC3C,yDAAqE;AAiBrE;;;;;;;;;;;GAWG;AACH,SAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,aAAa,EACb,WAAW,EACX,QAAQ,EACa;IACrB,MAAM,WAAW,GAAG,IAAA,mBAAW,EAAC,GAAS,EAAE;QACzC,WAAW,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,MAAM,WAAW,GAAG,IAAA,mBAAW,EAAC,GAAS,EAAE;QACzC,WAAW,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,OAAO,CACL;QAEE,uCAAK,SAAS,EAAC,oIAAoI;YACjJ,sCAAI,SAAS,EAAC,6CAA6C,IAAE,KAAK,CAAM;YACxE,uCAAK,SAAS,EAAC,kCAAkC;gBAC9C,aAAa;gBACd,0CACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,WAAW,EACpB,SAAS,EAAC,qJAAqJ;oBAE/J,8BAAC,qBAAW,IAAC,SAAS,EAAC,SAAS,GAAG;4BAE5B;gBACT,0CACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,WAAW,EACpB,SAAS,EAAC,wJAAwJ;oBAElK,8BAAC,mBAAS,IAAC,SAAS,EAAC,SAAS,GAAG;4BAE1B,CACL,CACF;QAGN,uCAAK,SAAS,EAAC,wBAAwB,IAAE,QAAQ,CAAO,CACpD,CACP,CAAC;AACJ,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Print enclosure component rendered inside the popup window.\n * @packageDocumentation\n */\n\nimport React, { useCallback } from 'react';\nimport { PrinterIcon, XMarkIcon } from '@heroicons/react/24/outline';\n\n/**\n * Props for {@link PrintEnclosure}.\n * @public\n */\nexport interface IPrintEnclosureProps {\n /** Title displayed in the toolbar. */\n readonly title: string;\n /** Optional extra controls rendered in the toolbar (e.g. toggles). */\n readonly toolbarExtras?: React.ReactNode;\n /** Reference to the popup window (used for print and close actions). */\n readonly popupWindow: Window;\n /** Content to display and print. */\n readonly children: React.ReactNode;\n}\n\n/**\n * A container component rendered inside a popup window that provides a\n * toolbar with Print and Close buttons and renders children as the\n * printable content.\n *\n * @remarks\n * The toolbar is hidden when printing via CSS (`print-toolbar` class).\n * Children are rendered at full width with no scroll constraints so\n * multi-page content flows naturally to the printer.\n *\n * @public\n */\nexport function PrintEnclosure({\n title,\n toolbarExtras,\n popupWindow,\n children\n}: IPrintEnclosureProps): React.JSX.Element {\n const handlePrint = useCallback((): void => {\n popupWindow.print();\n }, [popupWindow]);\n\n const handleClose = useCallback((): void => {\n popupWindow.close();\n }, [popupWindow]);\n\n return (\n <div>\n {/* Toolbar - hidden when printing */}\n <div className=\"print-toolbar sticky top-0 z-10 flex items-center justify-between gap-4 bg-surface border-b border-border px-6 py-3 mb-6 shadow-sm\">\n <h1 className=\"text-lg font-semibold text-primary truncate\">{title}</h1>\n <div className=\"flex items-center gap-3 shrink-0\">\n {toolbarExtras}\n <button\n type=\"button\"\n onClick={handlePrint}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-white bg-brand-primary hover:bg-brand-primary/90 rounded-md transition-colors\"\n >\n <PrinterIcon className=\"w-4 h-4\" />\n Print\n </button>\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-secondary bg-surface-raised hover:bg-surface-raised rounded-md transition-colors\"\n >\n <XMarkIcon className=\"w-4 h-4\" />\n Close\n </button>\n </div>\n </div>\n\n {/* Printable content */}\n <div className=\"max-w-4xl mx-auto px-6\">{children}</div>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/print/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/print/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,qDAA8E;AAArE,kHAAA,eAAe,OAAA;AACxB,mDAA6E;AAApE,gHAAA,cAAc,OAAA","sourcesContent":["/**\n * Print packlet - popup window for print-optimized content rendering.\n * @packageDocumentation\n */\n\nexport { openPrintWindow, type IPrintWindowOptions } from './openPrintWindow';\nexport { PrintEnclosure, type IPrintEnclosureProps } from './PrintEnclosure';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openPrintWindow.d.ts","sourceRoot":"","sources":["../../../src/packlets/print/openPrintWindow.tsx"],"names":[],"mappings":"AAsBA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1C;AAiBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAiExG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openPrintWindow.js","sourceRoot":"","sources":["../../../src/packlets/print/openPrintWindow.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;AAwDH,0CAiEC;AAvHD;;;GAGG;AAEH,kDAA0B;AAC1B,6CAA8C;AAE9C,qDAAkD;AAiBlD;;;GAGG;AACH,SAAS,WAAW,CAAC,MAAgB,EAAE,MAAgB;IACrD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAC5E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAgB,eAAe,CAAC,OAA2B,EAAE,OAA4B;IACvF,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAEpE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,KAAK,WAAW,MAAM,EAAE,CAAC,CAAC;IACrE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;;;;WAIZ,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA8B9B,CAAC,CAAC;IACR,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAEvB,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEtC,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IAC9D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,IAAA,mBAAU,EAAC,SAAS,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,CACT,8BAAC,+BAAc,IAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,IAC3E,OAAO,CACO,CAClB,CAAC;IAEF,KAAK,CAAC,gBAAgB,CAAC,cAAc,EAAE,GAAG,EAAE;QAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Opens a popup window for print-optimized content rendering.\n * @packageDocumentation\n */\n\nimport React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { PrintEnclosure } from './PrintEnclosure';\n\n/**\n * Options for {@link openPrintWindow}.\n * @public\n */\nexport interface IPrintWindowOptions {\n /** Title for the popup window. */\n readonly title: string;\n /** Width of the popup window in pixels (default 900). */\n readonly width?: number;\n /** Height of the popup window in pixels (default 700). */\n readonly height?: number;\n /** Extra toolbar controls to render in the print enclosure header. */\n readonly toolbarExtras?: React.ReactNode;\n}\n\n/**\n * Clones all stylesheet-related elements from the source document head\n * into the target document head so that styles are available in the popup.\n */\nfunction cloneStyles(source: Document, target: Document): void {\n const styles = Array.from(source.querySelectorAll('style'));\n for (const style of styles) {\n target.head.appendChild(style.cloneNode(true));\n }\n const links = Array.from(source.querySelectorAll('link[rel=\"stylesheet\"]'));\n for (const link of links) {\n target.head.appendChild(link.cloneNode(true));\n }\n}\n\n/**\n * Opens a popup window and renders the given React content inside a\n * {@link PrintEnclosure} with Print and Close toolbar buttons.\n *\n * @remarks\n * Must be called synchronously from a user click handler to avoid\n * popup blockers. If the popup is blocked, returns `null`.\n *\n * Styles are cloned from the parent document so that Tailwind and other\n * CSS frameworks work in the popup. An independent React root is created\n * in the popup (not a portal) so the popup is fully self-contained.\n *\n * @public\n */\nexport function openPrintWindow(content: React.ReactElement, options: IPrintWindowOptions): Window | null {\n const { title, width = 900, height = 700, toolbarExtras } = options;\n\n const popup = window.open('', '', `width=${width},height=${height}`);\n if (!popup) {\n return null;\n }\n\n popup.document.write(`<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\" />\n <title>${title.replace(/</g, '<')}</title>\n <style>\n @media screen {\n body {\n background: #f9fafb;\n padding: 2rem;\n margin: 0;\n }\n }\n @media print {\n body {\n margin: 0;\n padding: 0;\n background: white;\n }\n .print-toolbar {\n display: none !important;\n }\n .break-before-page {\n break-before: page;\n }\n .break-inside-avoid {\n break-inside: avoid;\n }\n }\n </style>\n</head>\n<body>\n <div id=\"print-root\"></div>\n</body>\n</html>`);\n popup.document.close();\n\n cloneStyles(document, popup.document);\n\n const container = popup.document.getElementById('print-root');\n if (!container) {\n popup.close();\n return null;\n }\n\n const root = createRoot(container);\n root.render(\n <PrintEnclosure title={title} toolbarExtras={toolbarExtras} popupWindow={popup}>\n {content}\n </PrintEnclosure>\n );\n\n popup.addEventListener('beforeunload', () => {\n root.unmount();\n });\n\n return popup;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResponsiveProvider.d.ts","sourceRoot":"","sources":["../../../src/packlets/responsive/ResponsiveProvider.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAuB,MAAM,uBAAuB,CAAC;AAMrG;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,gEAAgE;IAChE,QAAQ,CAAC,eAAe,CAAC,EAAE,UAAU,CAAC;IACtC,eAAe;IACf,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,eAAe,EACf,QAAQ,EACT,EAAE,wBAAwB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAG9C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,iBAAiB,CAMjD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResponsiveProvider.js","sourceRoot":"","sources":["../../../src/packlets/responsive/ResponsiveProvider.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCH,gDAMC;AAQD,sCAMC;AApDD,+CAAyD;AACzD,+DAAqG;AAErG,MAAM,iBAAiB,GAAiD,IAAA,qBAAa,EAEnF,SAAS,CAAC,CAAC;AAab;;;;;;;;;;;;;GAaG;AACH,SAAgB,kBAAkB,CAAC,EACjC,eAAe,EACf,QAAQ,EACiB;IACzB,MAAM,MAAM,GAAG,IAAA,yCAAmB,EAAC,eAAe,CAAC,CAAC;IACpD,OAAO,8BAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,IAAG,QAAQ,CAA8B,CAAC;AAC5F,CAAC;AAED;;;;;GAKG;AACH,SAAgB,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,iBAAiB,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport React, { createContext, useContext } from 'react';\nimport { type IResponsiveLayout, type LayoutMode, useResponsiveLayout } from './useResponsiveLayout';\n\nconst ResponsiveContext: React.Context<IResponsiveLayout | undefined> = createContext<\n IResponsiveLayout | undefined\n>(undefined);\n\n/**\n * Props for {@link ResponsiveProvider}.\n * @public\n */\nexport interface IResponsiveProviderProps {\n /** Optional layout mode override (for testing or storybook). */\n readonly forceLayoutMode?: LayoutMode;\n /** Children */\n readonly children: React.ReactNode;\n}\n\n/**\n * Provides responsive layout information to the component tree via context.\n *\n * Wrap your app (or a subtree) with this provider. Descendants use\n * {@link useResponsive} to read the current layout mode, device type, etc.\n *\n * @example\n * ```tsx\n * <ResponsiveProvider>\n * <App />\n * </ResponsiveProvider>\n * ```\n * @public\n */\nexport function ResponsiveProvider({\n forceLayoutMode,\n children\n}: IResponsiveProviderProps): React.JSX.Element {\n const layout = useResponsiveLayout(forceLayoutMode);\n return <ResponsiveContext.Provider value={layout}>{children}</ResponsiveContext.Provider>;\n}\n\n/**\n * Access the current responsive layout information.\n *\n * Must be called within a {@link ResponsiveProvider}.\n * @public\n */\nexport function useResponsive(): IResponsiveLayout {\n const context = useContext(ResponsiveContext);\n if (!context) {\n throw new Error('useResponsive must be used within a ResponsiveProvider');\n }\n return context;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/responsive/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,mBAAmB,EACnB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/responsive/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6DAM+B;AAL7B,0HAAA,mBAAmB,OAAA;AAOrB,2DAAwG;AAA/F,wHAAA,kBAAkB,OAAA;AAAE,mHAAA,aAAa,OAAA","sourcesContent":["/**\n * Responsive layout detection and context provider.\n * @packageDocumentation\n */\n\nexport {\n useResponsiveLayout,\n type DeviceType,\n type ScreenOrientation,\n type LayoutMode,\n type IResponsiveLayout\n} from './useResponsiveLayout';\n\nexport { ResponsiveProvider, useResponsive, type IResponsiveProviderProps } from './ResponsiveProvider';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResponsiveLayout.d.ts","sourceRoot":"","sources":["../../../src/packlets/responsive/useResponsiveLayout.ts"],"names":[],"mappings":"AAwBA;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzD;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAEhC,iCAAiC;IACjC,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;IAExC,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAEhC,+BAA+B;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,gCAAgC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B,8CAA8C;IAC9C,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAsED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,eAAe,CAAC,EAAE,UAAU,GAAG,iBAAiB,CA8BnF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResponsiveLayout.js","sourceRoot":"","sources":["../../../src/packlets/responsive/useResponsiveLayout.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport { useState, useEffect } from 'react';\n\n/**\n * Device type detection result.\n * @public\n */\nexport type DeviceType = 'mobile' | 'tablet' | 'desktop';\n\n/**\n * Screen orientation.\n * @public\n */\nexport type ScreenOrientation = 'portrait' | 'landscape';\n\n/**\n * Layout mode that drives structural rendering decisions.\n * - `full`: Desktop — sidebar visible, cascade columns side-by-side.\n * - `compact`: Tablet — sidebar as drawer, cascade still horizontal.\n * - `mobile`: Phone — sidebar as drawer, cascade becomes a view stack.\n * @public\n */\nexport type LayoutMode = 'full' | 'compact' | 'mobile';\n\n/**\n * Responsive layout information exposed by the hook and context.\n * @public\n */\nexport interface IResponsiveLayout {\n /** Device type based on screen size and touch capability */\n readonly deviceType: DeviceType;\n\n /** Current screen orientation */\n readonly orientation: ScreenOrientation;\n\n /** Structural layout mode driving component tree decisions */\n readonly layoutMode: LayoutMode;\n\n /** Viewport width in pixels */\n readonly screenWidth: number;\n\n /** Viewport height in pixels */\n readonly screenHeight: number;\n\n /** Whether the device supports touch input */\n readonly isTouchDevice: boolean;\n}\n\n/**\n * Breakpoints for responsive design (in CSS pixels).\n */\nconst BREAKPOINTS = {\n /** At or below this width, use mobile layout */\n mobile: 640,\n /** At or below this width, use compact layout */\n compact: 1024\n} as const;\n\n/**\n * Detect if the device supports touch input.\n */\nfunction detectTouchSupport(): boolean {\n return (\n 'ontouchstart' in window ||\n navigator.maxTouchPoints > 0 ||\n ((navigator as unknown as { msMaxTouchPoints?: number }).msMaxTouchPoints ?? 0) > 0\n );\n}\n\n/**\n * Determine device type from viewport dimensions and touch capability.\n */\nfunction determineDeviceType(width: number, isTouch: boolean): DeviceType {\n if (width <= BREAKPOINTS.mobile) {\n return 'mobile';\n }\n if (width <= BREAKPOINTS.compact && isTouch) {\n return 'tablet';\n }\n return 'desktop';\n}\n\n/**\n * Determine the structural layout mode from viewport width.\n */\nfunction determineLayoutMode(width: number): LayoutMode {\n if (width <= BREAKPOINTS.mobile) {\n return 'mobile';\n }\n if (width <= BREAKPOINTS.compact) {\n return 'compact';\n }\n return 'full';\n}\n\n/**\n * Compute the full layout info from current viewport state.\n */\nfunction computeLayout(forceLayoutMode?: LayoutMode): IResponsiveLayout {\n const width = window.innerWidth;\n const height = window.innerHeight;\n const isTouchDevice = detectTouchSupport();\n const orientation: ScreenOrientation = width > height ? 'landscape' : 'portrait';\n const deviceType = determineDeviceType(width, isTouchDevice);\n const layoutMode = forceLayoutMode ?? determineLayoutMode(width);\n\n return {\n deviceType,\n orientation,\n layoutMode,\n screenWidth: width,\n screenHeight: height,\n isTouchDevice\n };\n}\n\n/**\n * Hook that tracks responsive layout information for the current viewport.\n *\n * Listens to `resize` and `orientationchange` events and recomputes layout\n * on every change. Use the `layoutMode` field to drive structural rendering\n * decisions (e.g., sidebar as drawer vs. fixed panel).\n *\n * @param forceLayoutMode - Optional override for testing or storybook use.\n * @public\n */\nexport function useResponsiveLayout(forceLayoutMode?: LayoutMode): IResponsiveLayout {\n const [layout, setLayout] = useState<IResponsiveLayout>(() => computeLayout(forceLayoutMode));\n\n useEffect(() => {\n if (forceLayoutMode) {\n return;\n }\n\n function updateLayout(): void {\n setLayout(computeLayout());\n }\n\n window.addEventListener('resize', updateLayout);\n\n const onOrientationChange = (): void => {\n // Small delay to let the browser update viewport dimensions\n setTimeout(updateLayout, 100);\n };\n window.addEventListener('orientationchange', onOrientationChange);\n\n // Sync on mount in case viewport changed between SSR and hydration\n updateLayout();\n\n return () => {\n window.removeEventListener('resize', updateLayout);\n window.removeEventListener('orientationchange', onOrientationChange);\n };\n }, [forceLayoutMode]);\n\n return layout;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EntityRow.d.ts","sourceRoot":"","sources":["../../../src/packlets/selectors/EntityRow.tsx"],"names":[],"mappings":"AAsBA;;;;;;;;;;GAUG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAGjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAM3D;;;GAGG;AACH,MAAM,WAAW,eAAe,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IAC1D,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,wDAAwD;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IACrC,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IACvD,gEAAgE;IAChE,QAAQ,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxC,qDAAqD;IACrD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,YAAY,CA+XtG"}
|