@namroodinc/liquid-editorial 0.1.2 → 0.1.4
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/AGENTS.md +11 -0
- package/README.md +8 -0
- package/UPGRADING.md +56 -0
- package/dist/chunks/{EntryEditor-cjDk4vdH.cjs → EntryEditor-C32lKKnV.cjs} +2 -2
- package/dist/chunks/{EntryEditor-cjDk4vdH.cjs.map → EntryEditor-C32lKKnV.cjs.map} +1 -1
- package/dist/chunks/EntryEditor-xVuiqtFo.js +181 -0
- package/dist/chunks/{EntryEditor-BF808OZR.js.map → EntryEditor-xVuiqtFo.js.map} +1 -1
- package/dist/chunks/RichTextEditor-CSpjsL1z.js +357 -0
- package/dist/chunks/RichTextEditor-CSpjsL1z.js.map +1 -0
- package/dist/chunks/RichTextEditor-DC_0oN1s.cjs +2 -0
- package/dist/chunks/RichTextEditor-DC_0oN1s.cjs.map +1 -0
- package/dist/components/AssetGrid/index.js.map +1 -1
- package/dist/components/EntryEditor/index.cjs +1 -1
- package/dist/components/EntryEditor/index.js +3 -3
- package/dist/components/EntryPicker/index.cjs +1 -1
- package/dist/components/EntryPicker/index.cjs.map +1 -1
- package/dist/components/EntryPicker/index.js +4 -4
- package/dist/components/EntryPicker/index.js.map +1 -1
- package/dist/components/Field/index.js.map +1 -1
- package/dist/components/ImageCropper/index.js.map +1 -1
- package/dist/components/Modal/index.cjs +1 -1
- package/dist/components/Modal/index.cjs.map +1 -1
- package/dist/components/Modal/index.js +2 -2
- package/dist/components/Modal/index.js.map +1 -1
- package/dist/components/RichTextEditor/index.cjs +1 -1
- package/dist/components/RichTextEditor/index.d.cts.map +1 -1
- package/dist/components/RichTextEditor/index.d.ts.map +1 -1
- package/dist/components/RichTextEditor/index.js +3 -1
- package/dist/components/Table/index.cjs +1 -1
- package/dist/components/Table/index.cjs.map +1 -1
- package/dist/components/Table/index.d.cts +5 -1
- package/dist/components/Table/index.d.cts.map +1 -1
- package/dist/components/Table/index.d.ts +5 -1
- package/dist/components/Table/index.d.ts.map +1 -1
- package/dist/components/Table/index.js +74 -55
- package/dist/components/Table/index.js.map +1 -1
- package/dist/components/Table/style.css +4 -0
- package/dist/components/Time/index.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +13 -13
- package/package.json +3 -1
- package/dist/chunks/EntryEditor-BF808OZR.js +0 -181
- package/dist/chunks/RichTextEditor-DRt-kibg.js +0 -248
- package/dist/chunks/RichTextEditor-DRt-kibg.js.map +0 -1
- package/dist/chunks/RichTextEditor-tFkISOvq.cjs +0 -2
- package/dist/chunks/RichTextEditor-tFkISOvq.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Icon","useState","useMemo","_Fragment","Badge","SortableList","SortableListItem","Button","Modal","SearchField","require_Icon","require_components_Button_index","require_components_Badge_index","require_components_Modal_index","require_components_SearchField_index","require_components_SortableList_index","react","react_jsx_runtime","cx","parts","matches","query","item","Thumb","EntryPicker","internal","setInternal","defaultValue","selected","value","isOpen","setOpen","setQuery","byId","items","results","atMax","mode","max","commit","isDisabled","next","onValueChange","toggle","id","chosen","canReorder","isReorderable","row","className","label","emptyLabel","addLabel","event","isSelected","isBlocked"],"sources":["../../../src/components/EntryPicker/index.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport { Badge } from \"../Badge\";\nimport { Button } from \"../Button\";\nimport { Icon } from \"../Icon\";\nimport { Modal } from \"../Modal\";\nimport { SearchField } from \"../SearchField\";\nimport { SortableList, SortableListItem } from \"../SortableList\";\nimport \"./style.css\";\n\nfunction cx(...parts: (string | undefined | false)[]) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface EntryItem {\n id: string;\n title: string;\n /** Second line — a content type, a path, a file size. */\n subtitle?: string;\n /** Main image: an asset thumbnail, or the entry's hero. */\n imageUrl?: string;\n /** Words the search matches on top of the title and subtitle. */\n keywords?: string[];\n isDisabled?: boolean;\n}\n\nexport type EntryPickerMode = \"single\" | \"multiple\";\n\nexport interface EntryPickerProps {\n items: EntryItem[];\n /** Selected ids, in the order they will be stored. */\n value?: string[];\n defaultValue?: string[];\n onValueChange?: (value: string[]) => void;\n mode?: EntryPickerMode;\n /** Cap a multiple selection. Reaching it disables the unpicked rows. */\n max?: number;\n label?: string;\n /** Copy shown when nothing is picked yet. */\n emptyLabel?: string;\n addLabel?: string;\n /** Multiple selections are reorderable by default — the stored order is the shown order. */\n isReorderable?: boolean;\n isDisabled?: boolean;\n className?: string;\n}\n\nfunction matches(item: EntryItem, query: string) {\n if (!query) return true;\n const haystack = [item.title, item.subtitle, ...(item.keywords ?? [])]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(query.toLowerCase());\n}\n\nfunction Thumb({ item }: { item: EntryItem }) {\n return (\n <span className=\"ds-entry__thumb\">\n {item.imageUrl ? (\n <img src={item.imageUrl} alt=\"\" loading=\"lazy\" />\n ) : (\n <Icon name=\"file-text\" size={20} />\n )}\n </span>\n );\n}\n\n/**\n * Pick entries or assets out of a list. Search narrows it, a row toggles,\n * and a multiple selection keeps — and reorders — the order you chose.\n */\nexport function EntryPicker({\n items,\n value,\n defaultValue = [],\n onValueChange,\n mode = \"multiple\",\n max,\n label = \"Entries\",\n emptyLabel = \"Nothing selected yet.\",\n addLabel = \"Choose entries\",\n isReorderable = true,\n isDisabled = false,\n className,\n}: EntryPickerProps) {\n const [internal, setInternal] = useState<string[]>(defaultValue);\n const selected = value ?? internal;\n const [isOpen, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n\n const byId = useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);\n const results = useMemo(() => items.filter((item) => matches(item, query)), [items, query]);\n const atMax = mode === \"multiple\" && max !== undefined && selected.length >= max;\n\n const commit = (next: string[]) => {\n if (isDisabled) return;\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n\n const toggle = (id: string) => {\n if (mode === \"single\") {\n commit(selected[0] === id ? [] : [id]);\n setOpen(false);\n return;\n }\n if (selected.includes(id)) commit(selected.filter((item) => item !== id));\n else if (!atMax) commit([...selected, id]);\n };\n\n const chosen = selected.map((id) => byId.get(id) ?? { id, title: id });\n const canReorder = !isDisabled && isReorderable && mode === \"multiple\" && chosen.length > 1;\n\n const row = (item: EntryItem): ReactNode => (\n <>\n <Thumb item={item} />\n <span className=\"ds-entry__body\">\n <span className=\"ds-entry__title\">{item.title}</span>\n {item.subtitle && <span className=\"ds-entry__subtitle\">{item.subtitle}</span>}\n </span>\n </>\n );\n\n return (\n <div className={cx(\"ds-entry-picker\", className)}>\n <div className=\"ds-entry-picker__head\">\n <span className=\"ds-entry-picker__label\">{label}</span>\n <Badge shape=\"count\">{selected.length}</Badge>\n </div>\n\n {chosen.length === 0 ? (\n <p className=\"ds-entry-picker__empty\">{emptyLabel}</p>\n ) : canReorder ? (\n <SortableList\n items={selected}\n onReorder={commit}\n renderDragOverlay={(id) => {\n const item = byId.get(id);\n return item ? <div className=\"ds-entry\">{row(item)}</div> : null;\n }}\n >\n {chosen.map((item) => (\n <SortableListItem\n key={item.id}\n id={item.id}\n label={item.title}\n action={\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label={`Remove ${item.title}`}\n isDisabled={isDisabled}\n onClick={() => commit(selected.filter((id) => id !== item.id))}\n />\n }\n >\n <div className=\"ds-entry\">{row(item)}</div>\n </SortableListItem>\n ))}\n </SortableList>\n ) : (\n <ul className=\"ds-entry-picker__list\">\n {chosen.map((item) => (\n <li key={item.id} className=\"ds-entry-picker__row\">\n <div className=\"ds-entry\">{row(item)}</div>\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label={`Remove ${item.title}`}\n isDisabled={isDisabled}\n onClick={() => commit(selected.filter((id) => id !== item.id))}\n />\n </li>\n ))}\n </ul>\n )}\n\n <div className=\"ds-entry-picker__actions\">\n <Button\n variant=\"neutral\"\n size=\"sm\"\n iconStart=\"plus\"\n isDisabled={isDisabled}\n onClick={() => setOpen(true)}\n >\n {addLabel}\n </Button>\n {selected.length > 0 && (\n <Button variant=\"simple\" size=\"sm\" isDisabled={isDisabled} onClick={() => commit([])}>\n Clear\n </Button>\n )}\n </div>\n\n <Modal\n isOpen={isOpen}\n onClose={() => setOpen(false)}\n title={addLabel}\n description={\n mode === \"single\"\n ? \"Choose one entry.\"\n : max !== undefined\n ? `Choose up to ${max} entries.`\n : \"Choose as many entries as you need.\"\n }\n footer={\n <Button variant=\"primary\" onClick={() => setOpen(false)}>\n Done\n </Button>\n }\n >\n <div className=\"ds-entry-picker__search\">\n <SearchField\n value={query}\n placeholder=\"Search entries\"\n onChange={(event) => setQuery(event.target.value)}\n onClear={() => setQuery(\"\")}\n />\n </div>\n <ul className=\"ds-entry-picker__results\">\n {results.map((item) => {\n const isSelected = selected.includes(item.id);\n const isBlocked = isDisabled || item.isDisabled || (!isSelected && atMax);\n return (\n <li key={item.id}>\n <button\n type=\"button\"\n className=\"ds-entry-picker__result\"\n aria-pressed={isSelected}\n disabled={isBlocked || undefined}\n onClick={() => toggle(item.id)}\n >\n <div className=\"ds-entry\">{row(item)}</div>\n {isSelected && <Icon name=\"check\" size={20} />}\n </button>\n </li>\n );\n })}\n {results.length === 0 && (\n <li className=\"ds-entry-picker__no-results\">No entries match “{query}”.</li>\n )}\n </ul>\n </Modal>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Icon","useState","useMemo","_Fragment","Badge","SortableList","SortableListItem","Button","Modal","SearchField","require_Icon","require_components_Button_index","require_components_Modal_index","require_components_Badge_index","require_components_SearchField_index","require_components_SortableList_index","react","react_jsx_runtime","cx","parts","matches","query","item","Thumb","EntryPicker","internal","setInternal","defaultValue","selected","value","isOpen","setOpen","setQuery","byId","items","results","atMax","mode","max","commit","isDisabled","next","onValueChange","toggle","id","chosen","canReorder","isReorderable","row","className","label","emptyLabel","addLabel","event","isSelected","isBlocked"],"sources":["../../../src/components/EntryPicker/index.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport { Badge } from \"../Badge\";\nimport { Button } from \"../Button\";\nimport { Icon } from \"../Icon\";\nimport { Modal } from \"../Modal\";\nimport { SearchField } from \"../SearchField\";\nimport { SortableList, SortableListItem } from \"../SortableList\";\nimport \"./style.css\";\n\nfunction cx(...parts: (string | undefined | false)[]) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface EntryItem {\n id: string;\n title: string;\n /** Second line — a content type, a path, a file size. */\n subtitle?: string;\n /** Main image: an asset thumbnail, or the entry's hero. */\n imageUrl?: string;\n /** Words the search matches on top of the title and subtitle. */\n keywords?: string[];\n isDisabled?: boolean;\n}\n\nexport type EntryPickerMode = \"single\" | \"multiple\";\n\nexport interface EntryPickerProps {\n items: EntryItem[];\n /** Selected ids, in the order they will be stored. */\n value?: string[];\n defaultValue?: string[];\n onValueChange?: (value: string[]) => void;\n mode?: EntryPickerMode;\n /** Cap a multiple selection. Reaching it disables the unpicked rows. */\n max?: number;\n label?: string;\n /** Copy shown when nothing is picked yet. */\n emptyLabel?: string;\n addLabel?: string;\n /** Multiple selections are reorderable by default — the stored order is the shown order. */\n isReorderable?: boolean;\n isDisabled?: boolean;\n className?: string;\n}\n\nfunction matches(item: EntryItem, query: string) {\n if (!query) return true;\n const haystack = [item.title, item.subtitle, ...(item.keywords ?? [])]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(query.toLowerCase());\n}\n\nfunction Thumb({ item }: { item: EntryItem }) {\n return (\n <span className=\"ds-entry__thumb\">\n {item.imageUrl ? (\n <img src={item.imageUrl} alt=\"\" loading=\"lazy\" />\n ) : (\n <Icon name=\"file-text\" size={20} />\n )}\n </span>\n );\n}\n\n/**\n * Pick entries or assets out of a list. Search narrows it, a row toggles,\n * and a multiple selection keeps — and reorders — the order you chose.\n */\nexport function EntryPicker({\n items,\n value,\n defaultValue = [],\n onValueChange,\n mode = \"multiple\",\n max,\n label = \"Entries\",\n emptyLabel = \"Nothing selected yet.\",\n addLabel = \"Choose entries\",\n isReorderable = true,\n isDisabled = false,\n className,\n}: EntryPickerProps) {\n const [internal, setInternal] = useState<string[]>(defaultValue);\n const selected = value ?? internal;\n const [isOpen, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n\n const byId = useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);\n const results = useMemo(() => items.filter((item) => matches(item, query)), [items, query]);\n const atMax = mode === \"multiple\" && max !== undefined && selected.length >= max;\n\n const commit = (next: string[]) => {\n if (isDisabled) return;\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n\n const toggle = (id: string) => {\n if (mode === \"single\") {\n commit(selected[0] === id ? [] : [id]);\n setOpen(false);\n return;\n }\n if (selected.includes(id)) commit(selected.filter((item) => item !== id));\n else if (!atMax) commit([...selected, id]);\n };\n\n const chosen = selected.map((id) => byId.get(id) ?? { id, title: id });\n const canReorder = !isDisabled && isReorderable && mode === \"multiple\" && chosen.length > 1;\n\n const row = (item: EntryItem): ReactNode => (\n <>\n <Thumb item={item} />\n <span className=\"ds-entry__body\">\n <span className=\"ds-entry__title\">{item.title}</span>\n {item.subtitle && <span className=\"ds-entry__subtitle\">{item.subtitle}</span>}\n </span>\n </>\n );\n\n return (\n <div className={cx(\"ds-entry-picker\", className)}>\n <div className=\"ds-entry-picker__head\">\n <span className=\"ds-entry-picker__label\">{label}</span>\n <Badge shape=\"count\">{selected.length}</Badge>\n </div>\n\n {chosen.length === 0 ? (\n <p className=\"ds-entry-picker__empty\">{emptyLabel}</p>\n ) : canReorder ? (\n <SortableList\n items={selected}\n onReorder={commit}\n renderDragOverlay={(id) => {\n const item = byId.get(id);\n return item ? <div className=\"ds-entry\">{row(item)}</div> : null;\n }}\n >\n {chosen.map((item) => (\n <SortableListItem\n key={item.id}\n id={item.id}\n label={item.title}\n action={\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label={`Remove ${item.title}`}\n isDisabled={isDisabled}\n onClick={() => commit(selected.filter((id) => id !== item.id))}\n />\n }\n >\n <div className=\"ds-entry\">{row(item)}</div>\n </SortableListItem>\n ))}\n </SortableList>\n ) : (\n <ul className=\"ds-entry-picker__list\">\n {chosen.map((item) => (\n <li key={item.id} className=\"ds-entry-picker__row\">\n <div className=\"ds-entry\">{row(item)}</div>\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label={`Remove ${item.title}`}\n isDisabled={isDisabled}\n onClick={() => commit(selected.filter((id) => id !== item.id))}\n />\n </li>\n ))}\n </ul>\n )}\n\n <div className=\"ds-entry-picker__actions\">\n <Button\n variant=\"neutral\"\n size=\"sm\"\n iconStart=\"plus\"\n isDisabled={isDisabled}\n onClick={() => setOpen(true)}\n >\n {addLabel}\n </Button>\n {selected.length > 0 && (\n <Button variant=\"simple\" size=\"sm\" isDisabled={isDisabled} onClick={() => commit([])}>\n Clear\n </Button>\n )}\n </div>\n\n <Modal\n isOpen={isOpen}\n onClose={() => setOpen(false)}\n title={addLabel}\n description={\n mode === \"single\"\n ? \"Choose one entry.\"\n : max !== undefined\n ? `Choose up to ${max} entries.`\n : \"Choose as many entries as you need.\"\n }\n footer={\n <Button variant=\"primary\" onClick={() => setOpen(false)}>\n Done\n </Button>\n }\n >\n <div className=\"ds-entry-picker__search\">\n <SearchField\n value={query}\n placeholder=\"Search entries\"\n onChange={(event) => setQuery(event.target.value)}\n onClear={() => setQuery(\"\")}\n />\n </div>\n <ul className=\"ds-entry-picker__results\">\n {results.map((item) => {\n const isSelected = selected.includes(item.id);\n const isBlocked = isDisabled || item.isDisabled || (!isSelected && atMax);\n return (\n <li key={item.id}>\n <button\n type=\"button\"\n className=\"ds-entry-picker__result\"\n aria-pressed={isSelected}\n disabled={isBlocked || undefined}\n onClick={() => toggle(item.id)}\n >\n <div className=\"ds-entry\">{row(item)}</div>\n {isSelected && <Icon name=\"check\" size={20} />}\n </button>\n </li>\n );\n })}\n {results.length === 0 && (\n <li className=\"ds-entry-picker__no-results\">No entries match “{query}”.</li>\n )}\n </ul>\n </Modal>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as e } from "../../chunks/Icon-CGY1FNXT.js";
|
|
2
2
|
import { Button as t } from "../Button/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { Modal as n } from "../Modal/index.js";
|
|
4
|
+
import { Badge as r } from "../Badge/index.js";
|
|
5
5
|
import { SearchField as i } from "../SearchField/index.js";
|
|
6
6
|
import { SortableList as a, SortableListItem as o } from "../SortableList/index.js";
|
|
7
7
|
import { useMemo as s, useState as c } from "react";
|
|
@@ -56,7 +56,7 @@ function h({ items: h, value: g, defaultValue: _ = [], onValueChange: v, mode: y
|
|
|
56
56
|
children: [/* @__PURE__ */ u("span", {
|
|
57
57
|
className: "ds-entry-picker__label",
|
|
58
58
|
children: x
|
|
59
|
-
}), /* @__PURE__ */ u(
|
|
59
|
+
}), /* @__PURE__ */ u(r, {
|
|
60
60
|
shape: "count",
|
|
61
61
|
children: k.length
|
|
62
62
|
})]
|
|
@@ -126,7 +126,7 @@ function h({ items: h, value: g, defaultValue: _ = [], onValueChange: v, mode: y
|
|
|
126
126
|
children: "Clear"
|
|
127
127
|
})]
|
|
128
128
|
}),
|
|
129
|
-
/* @__PURE__ */ d(
|
|
129
|
+
/* @__PURE__ */ d(n, {
|
|
130
130
|
isOpen: A,
|
|
131
131
|
onClose: () => j(!1),
|
|
132
132
|
title: C,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_Fragment","Icon","cx","parts","matches","query","item","Thumb","EntryPicker","internal","setInternal","useState","defaultValue","selected","value","isOpen","setOpen","setQuery","byId","useMemo","items","results","atMax","mode","max","commit","isDisabled","next","onValueChange","toggle","id","chosen","canReorder","isReorderable","row","Fragment","className","label","Badge","emptyLabel","SortableList","SortableListItem","Button","addLabel","Modal","SearchField","event","isSelected","isBlocked"],"sources":["../../../src/components/EntryPicker/index.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport { Badge } from \"../Badge\";\nimport { Button } from \"../Button\";\nimport { Icon } from \"../Icon\";\nimport { Modal } from \"../Modal\";\nimport { SearchField } from \"../SearchField\";\nimport { SortableList, SortableListItem } from \"../SortableList\";\nimport \"./style.css\";\n\nfunction cx(...parts: (string | undefined | false)[]) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface EntryItem {\n id: string;\n title: string;\n /** Second line — a content type, a path, a file size. */\n subtitle?: string;\n /** Main image: an asset thumbnail, or the entry's hero. */\n imageUrl?: string;\n /** Words the search matches on top of the title and subtitle. */\n keywords?: string[];\n isDisabled?: boolean;\n}\n\nexport type EntryPickerMode = \"single\" | \"multiple\";\n\nexport interface EntryPickerProps {\n items: EntryItem[];\n /** Selected ids, in the order they will be stored. */\n value?: string[];\n defaultValue?: string[];\n onValueChange?: (value: string[]) => void;\n mode?: EntryPickerMode;\n /** Cap a multiple selection. Reaching it disables the unpicked rows. */\n max?: number;\n label?: string;\n /** Copy shown when nothing is picked yet. */\n emptyLabel?: string;\n addLabel?: string;\n /** Multiple selections are reorderable by default — the stored order is the shown order. */\n isReorderable?: boolean;\n isDisabled?: boolean;\n className?: string;\n}\n\nfunction matches(item: EntryItem, query: string) {\n if (!query) return true;\n const haystack = [item.title, item.subtitle, ...(item.keywords ?? [])]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(query.toLowerCase());\n}\n\nfunction Thumb({ item }: { item: EntryItem }) {\n return (\n <span className=\"ds-entry__thumb\">\n {item.imageUrl ? (\n <img src={item.imageUrl} alt=\"\" loading=\"lazy\" />\n ) : (\n <Icon name=\"file-text\" size={20} />\n )}\n </span>\n );\n}\n\n/**\n * Pick entries or assets out of a list. Search narrows it, a row toggles,\n * and a multiple selection keeps — and reorders — the order you chose.\n */\nexport function EntryPicker({\n items,\n value,\n defaultValue = [],\n onValueChange,\n mode = \"multiple\",\n max,\n label = \"Entries\",\n emptyLabel = \"Nothing selected yet.\",\n addLabel = \"Choose entries\",\n isReorderable = true,\n isDisabled = false,\n className,\n}: EntryPickerProps) {\n const [internal, setInternal] = useState<string[]>(defaultValue);\n const selected = value ?? internal;\n const [isOpen, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n\n const byId = useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);\n const results = useMemo(() => items.filter((item) => matches(item, query)), [items, query]);\n const atMax = mode === \"multiple\" && max !== undefined && selected.length >= max;\n\n const commit = (next: string[]) => {\n if (isDisabled) return;\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n\n const toggle = (id: string) => {\n if (mode === \"single\") {\n commit(selected[0] === id ? [] : [id]);\n setOpen(false);\n return;\n }\n if (selected.includes(id)) commit(selected.filter((item) => item !== id));\n else if (!atMax) commit([...selected, id]);\n };\n\n const chosen = selected.map((id) => byId.get(id) ?? { id, title: id });\n const canReorder = !isDisabled && isReorderable && mode === \"multiple\" && chosen.length > 1;\n\n const row = (item: EntryItem): ReactNode => (\n <>\n <Thumb item={item} />\n <span className=\"ds-entry__body\">\n <span className=\"ds-entry__title\">{item.title}</span>\n {item.subtitle && <span className=\"ds-entry__subtitle\">{item.subtitle}</span>}\n </span>\n </>\n );\n\n return (\n <div className={cx(\"ds-entry-picker\", className)}>\n <div className=\"ds-entry-picker__head\">\n <span className=\"ds-entry-picker__label\">{label}</span>\n <Badge shape=\"count\">{selected.length}</Badge>\n </div>\n\n {chosen.length === 0 ? (\n <p className=\"ds-entry-picker__empty\">{emptyLabel}</p>\n ) : canReorder ? (\n <SortableList\n items={selected}\n onReorder={commit}\n renderDragOverlay={(id) => {\n const item = byId.get(id);\n return item ? <div className=\"ds-entry\">{row(item)}</div> : null;\n }}\n >\n {chosen.map((item) => (\n <SortableListItem\n key={item.id}\n id={item.id}\n label={item.title}\n action={\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label={`Remove ${item.title}`}\n isDisabled={isDisabled}\n onClick={() => commit(selected.filter((id) => id !== item.id))}\n />\n }\n >\n <div className=\"ds-entry\">{row(item)}</div>\n </SortableListItem>\n ))}\n </SortableList>\n ) : (\n <ul className=\"ds-entry-picker__list\">\n {chosen.map((item) => (\n <li key={item.id} className=\"ds-entry-picker__row\">\n <div className=\"ds-entry\">{row(item)}</div>\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label={`Remove ${item.title}`}\n isDisabled={isDisabled}\n onClick={() => commit(selected.filter((id) => id !== item.id))}\n />\n </li>\n ))}\n </ul>\n )}\n\n <div className=\"ds-entry-picker__actions\">\n <Button\n variant=\"neutral\"\n size=\"sm\"\n iconStart=\"plus\"\n isDisabled={isDisabled}\n onClick={() => setOpen(true)}\n >\n {addLabel}\n </Button>\n {selected.length > 0 && (\n <Button variant=\"simple\" size=\"sm\" isDisabled={isDisabled} onClick={() => commit([])}>\n Clear\n </Button>\n )}\n </div>\n\n <Modal\n isOpen={isOpen}\n onClose={() => setOpen(false)}\n title={addLabel}\n description={\n mode === \"single\"\n ? \"Choose one entry.\"\n : max !== undefined\n ? `Choose up to ${max} entries.`\n : \"Choose as many entries as you need.\"\n }\n footer={\n <Button variant=\"primary\" onClick={() => setOpen(false)}>\n Done\n </Button>\n }\n >\n <div className=\"ds-entry-picker__search\">\n <SearchField\n value={query}\n placeholder=\"Search entries\"\n onChange={(event) => setQuery(event.target.value)}\n onClear={() => setQuery(\"\")}\n />\n </div>\n <ul className=\"ds-entry-picker__results\">\n {results.map((item) => {\n const isSelected = selected.includes(item.id);\n const isBlocked = isDisabled || item.isDisabled || (!isSelected && atMax);\n return (\n <li key={item.id}>\n <button\n type=\"button\"\n className=\"ds-entry-picker__result\"\n aria-pressed={isSelected}\n disabled={isBlocked || undefined}\n onClick={() => toggle(item.id)}\n >\n <div className=\"ds-entry\">{row(item)}</div>\n {isSelected && <Icon name=\"check\" size={20} />}\n </button>\n </li>\n );\n })}\n {results.length === 0 && (\n <li className=\"ds-entry-picker__no-results\">No entries match “{query}”.</li>\n )}\n </ul>\n </Modal>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["_Fragment","Icon","Fragment$1","cx","parts","matches","query","item","Thumb","EntryPicker","internal","setInternal","useState","defaultValue","selected","value","isOpen","setOpen","setQuery","byId","useMemo","items","results","atMax","mode","max","commit","isDisabled","next","onValueChange","toggle","id","chosen","canReorder","isReorderable","row","className","label","Badge","emptyLabel","SortableList","SortableListItem","Button","addLabel","Modal","SearchField","event","isSelected","isBlocked"],"sources":["../../../src/components/EntryPicker/index.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport { Badge } from \"../Badge\";\nimport { Button } from \"../Button\";\nimport { Icon } from \"../Icon\";\nimport { Modal } from \"../Modal\";\nimport { SearchField } from \"../SearchField\";\nimport { SortableList, SortableListItem } from \"../SortableList\";\nimport \"./style.css\";\n\nfunction cx(...parts: (string | undefined | false)[]) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface EntryItem {\n id: string;\n title: string;\n /** Second line — a content type, a path, a file size. */\n subtitle?: string;\n /** Main image: an asset thumbnail, or the entry's hero. */\n imageUrl?: string;\n /** Words the search matches on top of the title and subtitle. */\n keywords?: string[];\n isDisabled?: boolean;\n}\n\nexport type EntryPickerMode = \"single\" | \"multiple\";\n\nexport interface EntryPickerProps {\n items: EntryItem[];\n /** Selected ids, in the order they will be stored. */\n value?: string[];\n defaultValue?: string[];\n onValueChange?: (value: string[]) => void;\n mode?: EntryPickerMode;\n /** Cap a multiple selection. Reaching it disables the unpicked rows. */\n max?: number;\n label?: string;\n /** Copy shown when nothing is picked yet. */\n emptyLabel?: string;\n addLabel?: string;\n /** Multiple selections are reorderable by default — the stored order is the shown order. */\n isReorderable?: boolean;\n isDisabled?: boolean;\n className?: string;\n}\n\nfunction matches(item: EntryItem, query: string) {\n if (!query) return true;\n const haystack = [item.title, item.subtitle, ...(item.keywords ?? [])]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(query.toLowerCase());\n}\n\nfunction Thumb({ item }: { item: EntryItem }) {\n return (\n <span className=\"ds-entry__thumb\">\n {item.imageUrl ? (\n <img src={item.imageUrl} alt=\"\" loading=\"lazy\" />\n ) : (\n <Icon name=\"file-text\" size={20} />\n )}\n </span>\n );\n}\n\n/**\n * Pick entries or assets out of a list. Search narrows it, a row toggles,\n * and a multiple selection keeps — and reorders — the order you chose.\n */\nexport function EntryPicker({\n items,\n value,\n defaultValue = [],\n onValueChange,\n mode = \"multiple\",\n max,\n label = \"Entries\",\n emptyLabel = \"Nothing selected yet.\",\n addLabel = \"Choose entries\",\n isReorderable = true,\n isDisabled = false,\n className,\n}: EntryPickerProps) {\n const [internal, setInternal] = useState<string[]>(defaultValue);\n const selected = value ?? internal;\n const [isOpen, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n\n const byId = useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);\n const results = useMemo(() => items.filter((item) => matches(item, query)), [items, query]);\n const atMax = mode === \"multiple\" && max !== undefined && selected.length >= max;\n\n const commit = (next: string[]) => {\n if (isDisabled) return;\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n\n const toggle = (id: string) => {\n if (mode === \"single\") {\n commit(selected[0] === id ? [] : [id]);\n setOpen(false);\n return;\n }\n if (selected.includes(id)) commit(selected.filter((item) => item !== id));\n else if (!atMax) commit([...selected, id]);\n };\n\n const chosen = selected.map((id) => byId.get(id) ?? { id, title: id });\n const canReorder = !isDisabled && isReorderable && mode === \"multiple\" && chosen.length > 1;\n\n const row = (item: EntryItem): ReactNode => (\n <>\n <Thumb item={item} />\n <span className=\"ds-entry__body\">\n <span className=\"ds-entry__title\">{item.title}</span>\n {item.subtitle && <span className=\"ds-entry__subtitle\">{item.subtitle}</span>}\n </span>\n </>\n );\n\n return (\n <div className={cx(\"ds-entry-picker\", className)}>\n <div className=\"ds-entry-picker__head\">\n <span className=\"ds-entry-picker__label\">{label}</span>\n <Badge shape=\"count\">{selected.length}</Badge>\n </div>\n\n {chosen.length === 0 ? (\n <p className=\"ds-entry-picker__empty\">{emptyLabel}</p>\n ) : canReorder ? (\n <SortableList\n items={selected}\n onReorder={commit}\n renderDragOverlay={(id) => {\n const item = byId.get(id);\n return item ? <div className=\"ds-entry\">{row(item)}</div> : null;\n }}\n >\n {chosen.map((item) => (\n <SortableListItem\n key={item.id}\n id={item.id}\n label={item.title}\n action={\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label={`Remove ${item.title}`}\n isDisabled={isDisabled}\n onClick={() => commit(selected.filter((id) => id !== item.id))}\n />\n }\n >\n <div className=\"ds-entry\">{row(item)}</div>\n </SortableListItem>\n ))}\n </SortableList>\n ) : (\n <ul className=\"ds-entry-picker__list\">\n {chosen.map((item) => (\n <li key={item.id} className=\"ds-entry-picker__row\">\n <div className=\"ds-entry\">{row(item)}</div>\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label={`Remove ${item.title}`}\n isDisabled={isDisabled}\n onClick={() => commit(selected.filter((id) => id !== item.id))}\n />\n </li>\n ))}\n </ul>\n )}\n\n <div className=\"ds-entry-picker__actions\">\n <Button\n variant=\"neutral\"\n size=\"sm\"\n iconStart=\"plus\"\n isDisabled={isDisabled}\n onClick={() => setOpen(true)}\n >\n {addLabel}\n </Button>\n {selected.length > 0 && (\n <Button variant=\"simple\" size=\"sm\" isDisabled={isDisabled} onClick={() => commit([])}>\n Clear\n </Button>\n )}\n </div>\n\n <Modal\n isOpen={isOpen}\n onClose={() => setOpen(false)}\n title={addLabel}\n description={\n mode === \"single\"\n ? \"Choose one entry.\"\n : max !== undefined\n ? `Choose up to ${max} entries.`\n : \"Choose as many entries as you need.\"\n }\n footer={\n <Button variant=\"primary\" onClick={() => setOpen(false)}>\n Done\n </Button>\n }\n >\n <div className=\"ds-entry-picker__search\">\n <SearchField\n value={query}\n placeholder=\"Search entries\"\n onChange={(event) => setQuery(event.target.value)}\n onClear={() => setQuery(\"\")}\n />\n </div>\n <ul className=\"ds-entry-picker__results\">\n {results.map((item) => {\n const isSelected = selected.includes(item.id);\n const isBlocked = isDisabled || item.isDisabled || (!isSelected && atMax);\n return (\n <li key={item.id}>\n <button\n type=\"button\"\n className=\"ds-entry-picker__result\"\n aria-pressed={isSelected}\n disabled={isBlocked || undefined}\n onClick={() => toggle(item.id)}\n >\n <div className=\"ds-entry\">{row(item)}</div>\n {isSelected && <Icon name=\"check\" size={20} />}\n </button>\n </li>\n );\n })}\n {results.length === 0 && (\n <li className=\"ds-entry-picker__no-results\">No entries match “{query}”.</li>\n )}\n </ul>\n </Modal>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_Fragment","Field","id","useId","hintId","errorId","describedBy","error","hint","labelId","Wrapper","isGroup","labelContent","
|
|
1
|
+
{"version":3,"file":"index.js","names":["_Fragment","Fragment$1","Field","id","useId","hintId","errorId","describedBy","error","hint","labelId","Wrapper","isGroup","labelContent","label","isRequired","children"],"sources":["../../../src/components/Field/index.tsx"],"sourcesContent":["import { useId, type ReactNode } from \"react\";\nimport \"../Field/style.css\";\n\nexport type FieldSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface FieldProps {\n label: string;\n hint?: string;\n /** Present means invalid: the message renders and the control is marked. */\n error?: string;\n isRequired?: boolean;\n /** Use a legend for a field containing a group of controls. */\n isGroup?: boolean;\n /** Receives the ids and invalid flag the control must carry. */\n children: (props: {\n id: string;\n \"aria-describedby\"?: string;\n \"aria-labelledby\": string;\n \"aria-invalid\"?: true;\n required?: boolean;\n }) => ReactNode;\n}\n\n/** Label, hint, error and required marker around any control wearing the field skin. */\nexport function Field({ label, hint, error, isRequired, isGroup = false, children }: FieldProps) {\n const id = useId();\n const hintId = `${id}-hint`;\n const errorId = `${id}-error`;\n const describedBy = error ? errorId : hint ? hintId : undefined;\n const labelId = `${id}-label`;\n const Wrapper = isGroup ? \"fieldset\" : \"div\";\n const labelContent = <>{label}{isRequired && <span className=\"ds-field__required\" aria-hidden=\"true\">*</span>}</>;\n\n return (\n <Wrapper className=\"ds-field\">\n {isGroup\n ? <legend id={labelId} className=\"ds-field__label\">{labelContent}</legend>\n : <label id={labelId} className=\"ds-field__label\" htmlFor={id}>{labelContent}</label>}\n {children({\n id,\n \"aria-describedby\": describedBy,\n \"aria-labelledby\": labelId,\n \"aria-invalid\": error ? true : undefined,\n required: isRequired,\n })}\n {hint && !error && (\n <span className=\"ds-field__hint\" id={hintId}>\n {hint}\n </span>\n )}\n {error && (\n <span className=\"ds-field__error\" id={errorId}>\n {error}\n </span>\n )}\n </Wrapper>\n );\n}\n"],"mappings":";;;;AAwBA,SAAgBE,EAAM,EAAE,UAAO,SAAM,UAAO,eAAY,aAAU,IAAO,eAAwB;CAC/F,IAAMC,IAAKC,EAAM,GACXC,IAAS,GAAGF,EAAG,QACfG,IAAU,GAAGH,EAAG,SAChBI,IAAcC,IAAQF,IAAUG,IAAOJ,IAAS,KAAA,GAChDK,IAAU,GAAGP,EAAG,SAChBQ,IAAUC,IAAU,aAAa,OACjCC,IAAe,kBAAAb,GAAA,EAAA,UAAA,CAAGc,GAAOC,KAAc,kBAAC,QAAD;EAAM,WAAU;EAAqB,eAAY;EAAO,UAAA;CAAO,CAAA,CAAI,EAAA,CAAA;CAEhH,OACE,kBAACJ,GAAD;EAAS,WAAU;EAAnB,UAAA;GACGC,IACG,kBAAC,UAAD;IAAQ,IAAIF;IAAS,WAAU;IAAmB,UAAAG;GAAqB,CAAA,IACvE,kBAAC,SAAD;IAAO,IAAIH;IAAS,WAAU;IAAkB,SAASP;IAAK,UAAAU;GAAoB,CAAA;GACrFG,EAAS;IACR;IACA,oBAAoBT;IACpB,mBAAmBG;IACnB,gBAAgBF,IAAQ,KAAO,KAAA;IAC/B,UAAUO;GACZ,CAAC;GACAN,KAAQ,CAACD,KACR,kBAAC,QAAD;IAAM,WAAU;IAAiB,IAAIH;IAClC,UAAAI;GACG,CAAA;GAEPD,KACC,kBAAC,QAAD;IAAM,WAAU;IAAkB,IAAIF;IACnC,UAAAE;GACG,CAAA;EAED;;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_Fragment","cropRatios","MIN_ZOOM","REST","ImageCropper","forwardRef","rest","frameRef","useRef","frame","setFrame","useState","natural","setNatural","state","setState","ratio","setRatio","aspect","dragRef","imageRef","prev","chooseRatio","next","onAspectChange","turn","by","adopt","useCallback","img","src","quarter","view","baseScale","scale","maxOffsetX","maxOffsetY","node","measure","observer","clamp","nextScale","limitX","limitY","maxZoom","width","height","onPointerDown","event","onPointerMove","drag","dx","dy","endDrag","nudge","className","ratios","ButtonGroup","Button","option","step","move","rotatable","Fragment","cropToBlob","image","rotation","turned","turnedContext","outputWidth","crop","canvas","context","blob","resolve","reject","type","quality"],"sources":["../../../src/components/ImageCropper/index.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { Button } from \"../Button\";\nimport { ButtonGroup } from \"../ButtonGroup\";\nimport \"./style.css\";\n\nexport interface CropRect {\n /** Left edge of the crop, in the (rotated) image's own pixels. */\n x: number;\n /** Top edge of the crop, in the (rotated) image's own pixels. */\n y: number;\n width: number;\n height: number;\n}\n\nexport interface CropState {\n /** Pan, in stage pixels, from the centre. */\n offsetX: number;\n offsetY: number;\n /** 1 is \"cover the crop window exactly\". */\n zoom: number;\n /** Quarter turns applied to the picture, clockwise: 0, 90, 180 or 270. */\n rotation: number;\n}\n\n/** One offered output shape. `value` is width / height. */\nexport interface CropRatio {\n label: string;\n value: number;\n}\n\n/** The house set: square, portrait, landscape, wide. */\nexport const cropRatios: CropRatio[] = [\n { label: \"1:1\", value: 1 },\n { label: \"4:5\", value: 4 / 5 },\n { label: \"4:3\", value: 4 / 3 },\n { label: \"16:9\", value: 16 / 9 },\n];\n\nexport interface ImageCropperProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n src: string;\n /** Describes the picture for people who cannot see the stage. */\n alt?: string;\n /** Output shape, width / height. 1 for an avatar, 16 / 9 for a hero. */\n aspect?: number;\n /**\n * Offer the reader a choice of output shapes. Omit it — or pass one ratio —\n * when the shape is fixed by the slot the picture is going into.\n */\n ratios?: CropRatio[];\n /** Fires when the reader picks a different shape. */\n onAspectChange?: (aspect: number) => void;\n /** Highest allowed zoom. Past 3 the result is mush on most uploads. */\n maxZoom?: number;\n /** Offer the quarter-turn controls. */\n rotatable?: boolean;\n /** Fires on every pan, zoom, turn and reset, with the crop in image pixels. */\n onChange?: (crop: CropRect, state: CropState) => void;\n}\n\nconst MIN_ZOOM = 1;\nconst REST: CropState = { offsetX: 0, offsetY: 0, zoom: 1, rotation: 0 };\n\n/**\n * Pan-and-zoom cropping over a fixed frame. The frame never moves — the\n * picture does — and the parts that fall outside it stay visible under a\n * veil, so the reader can see what they are trimming away.\n * Drag with a pointer, or focus the stage and use the arrow keys.\n */\nexport const ImageCropper = forwardRef<HTMLDivElement, ImageCropperProps>(\n function ImageCropper(\n {\n src,\n alt = \"\",\n aspect = 1,\n ratios,\n onAspectChange,\n maxZoom = 3,\n rotatable = true,\n onChange,\n className,\n ...rest\n },\n ref,\n ) {\n const frameRef = useRef<HTMLDivElement | null>(null);\n const [frame, setFrame] = useState({ width: 0, height: 0 });\n const [natural, setNatural] = useState({ width: 0, height: 0 });\n const [state, setState] = useState<CropState>(REST);\n const [ratio, setRatio] = useState(aspect);\n const dragRef = useRef<{ pointerId: number; x: number; y: number } | null>(null);\n const imageRef = useRef<HTMLImageElement | null>(null);\n\n // The prop stays the source of truth when the caller drives the shape.\n useEffect(() => {\n setRatio(aspect);\n setState((prev) => ({ ...REST, rotation: prev.rotation }));\n }, [aspect]);\n\n const chooseRatio = (next: number) => {\n setRatio(next);\n setState((prev) => ({ ...REST, rotation: prev.rotation }));\n onAspectChange?.(next);\n };\n\n const turn = (by: number) =>\n setState((prev) => ({ ...REST, rotation: (prev.rotation + by + 360) % 360 }));\n\n /** Take the picture's own pixels and start from a centred, unzoomed view. */\n const adopt = useCallback((img: HTMLImageElement) => {\n if (!img.naturalWidth) return;\n setNatural({ width: img.naturalWidth, height: img.naturalHeight });\n setState(REST);\n }, []);\n\n // A cached or server-rendered image can already be decoded before React\n // attaches onLoad, and then that event never fires.\n useEffect(() => {\n const img = imageRef.current;\n if (img?.complete) adopt(img);\n }, [adopt, src]);\n\n // After a quarter turn the picture presents its other side to the frame.\n const quarter = state.rotation % 180 !== 0;\n const view = {\n width: quarter ? natural.height : natural.width,\n height: quarter ? natural.width : natural.height,\n };\n\n // The scale at which the image exactly covers the frame; zoom multiplies it.\n const baseScale =\n view.width && frame.width\n ? Math.max(frame.width / view.width, frame.height / view.height)\n : 0;\n const scale = baseScale * state.zoom;\n const maxOffsetX = scale ? Math.max(0, (view.width * scale - frame.width) / 2) : 0;\n const maxOffsetY = scale ? Math.max(0, (view.height * scale - frame.height) / 2) : 0;\n\n useLayoutEffect(() => {\n const node = frameRef.current;\n if (!node) return;\n const measure = () =>\n setFrame({ width: node.clientWidth, height: node.clientHeight });\n measure();\n const observer = new ResizeObserver(measure);\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const clamp = useCallback(\n (next: CropState): CropState => {\n const nextScale = baseScale * next.zoom;\n const limitX = nextScale\n ? Math.max(0, (view.width * nextScale - frame.width) / 2)\n : 0;\n const limitY = nextScale\n ? Math.max(0, (view.height * nextScale - frame.height) / 2)\n : 0;\n return {\n rotation: next.rotation,\n zoom: Math.min(maxZoom, Math.max(MIN_ZOOM, next.zoom)),\n offsetX: Math.min(limitX, Math.max(-limitX, next.offsetX)),\n offsetY: Math.min(limitY, Math.max(-limitY, next.offsetY)),\n };\n },\n [baseScale, maxZoom, view.height, view.width, frame.height, frame.width],\n );\n\n useEffect(() => {\n if (!scale || !frame.width) return;\n const width = frame.width / scale;\n const height = frame.height / scale;\n onChange?.(\n {\n x: Math.round(view.width / 2 - state.offsetX / scale - width / 2),\n y: Math.round(view.height / 2 - state.offsetY / scale - height / 2),\n width: Math.round(width),\n height: Math.round(height),\n },\n state,\n );\n // onChange is intentionally not a dependency: callers pass inline handlers.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scale, frame.width, frame.height, view.width, view.height, state]);\n\n const onPointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (event.button !== 0) return;\n dragRef.current = { pointerId: event.pointerId, x: event.clientX, y: event.clientY };\n event.currentTarget.setPointerCapture(event.pointerId);\n };\n\n const onPointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== event.pointerId) return;\n const dx = event.clientX - drag.x;\n const dy = event.clientY - drag.y;\n dragRef.current = { ...drag, x: event.clientX, y: event.clientY };\n setState((prev) => clamp({ ...prev, offsetX: prev.offsetX + dx, offsetY: prev.offsetY + dy }));\n };\n\n const endDrag = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (dragRef.current?.pointerId !== event.pointerId) return;\n dragRef.current = null;\n event.currentTarget.releasePointerCapture?.(event.pointerId);\n };\n\n const nudge = (dx: number, dy: number) =>\n setState((prev) => clamp({ ...prev, offsetX: prev.offsetX + dx, offsetY: prev.offsetY + dy }));\n\n return (\n <div ref={ref} className={[\"ds-cropper\", className].filter(Boolean).join(\" \")} {...rest}>\n {ratios && ratios.length > 1 && (\n <ButtonGroup aria-label=\"Crop ratio\" className=\"ds-cropper__ratios\">\n {ratios.map((option) => (\n <Button\n key={option.label}\n size=\"sm\"\n variant={option.value === ratio ? \"active\" : \"neutral\"}\n aria-pressed={option.value === ratio}\n onClick={() => chooseRatio(option.value)}\n >\n {option.label}\n </Button>\n ))}\n </ButtonGroup>\n )}\n <div\n role=\"application\"\n aria-label=\"Crop area — drag to reposition, arrow keys to nudge\"\n tabIndex={0}\n className=\"ds-cropper__stage\"\n style={{ \"--cropper-aspect\": String(ratio) } as CSSProperties}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onKeyDown={(event) => {\n const step = event.shiftKey ? 24 : 8;\n const moves: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, -step],\n ArrowDown: [0, step],\n };\n const move = moves[event.key];\n if (!move) return;\n event.preventDefault();\n nudge(move[0], move[1]);\n }}\n >\n <img\n ref={imageRef}\n src={src}\n alt={alt}\n draggable={false}\n className=\"ds-cropper__image\"\n onLoad={(event) => adopt(event.currentTarget)}\n style={{\n inlineSize: natural.width * scale || undefined,\n blockSize: natural.height * scale || undefined,\n transform: `translate(calc(-50% + ${state.offsetX}px), calc(-50% + ${state.offsetY}px)) rotate(${state.rotation}deg)`,\n }}\n />\n {/* The window: everything outside it is veiled, not hidden. */}\n <div className=\"ds-cropper__frame\" ref={frameRef} aria-hidden=\"true\">\n <div className=\"ds-cropper__guides\" />\n </div>\n </div>\n\n <div className=\"ds-cropper__controls\">\n <label className=\"ds-cropper__zoom\">\n <span className=\"ds-cropper__zoom-label\">Zoom</span>\n <input\n type=\"range\"\n min={MIN_ZOOM}\n max={maxZoom}\n step={0.01}\n value={state.zoom}\n className=\"ds-cropper__slider\"\n onChange={(event) =>\n setState((prev) => clamp({ ...prev, zoom: Number(event.target.value) }))\n }\n />\n <span className=\"ds-cropper__value\">{state.zoom.toFixed(2)}×</span>\n </label>\n <ButtonGroup aria-label=\"Crop actions\">\n {rotatable && (\n <>\n <Button\n size=\"sm\"\n iconStart=\"rotate-ccw\"\n aria-label=\"Rotate left\"\n onClick={() => turn(-90)}\n />\n <Button\n size=\"sm\"\n iconStart=\"rotate-cw\"\n aria-label=\"Rotate right\"\n onClick={() => turn(90)}\n />\n </>\n )}\n <Button size=\"sm\" onClick={() => setState(REST)}>\n Reset\n </Button>\n </ButtonGroup>\n </div>\n\n <p className=\"ds-cropper__hint\">\n Drag the picture to reposition it. Nothing is written until you save —{\" \"}\n {maxOffsetX === 0 && maxOffsetY === 0\n ? \"at this zoom the whole picture is in frame.\"\n : \"the veiled edges are what gets trimmed.\"}\n </p>\n </div>\n );\n },\n);\n\nexport interface CropToBlobOptions {\n /** Width of the output in pixels; the height follows the crop's aspect. */\n outputWidth?: number;\n /** Quarter turns applied before cropping — pass `state.rotation`. */\n rotation?: number;\n type?: \"image/png\" | \"image/jpeg\" | \"image/webp\";\n quality?: number;\n}\n\n/**\n * Renders a `CropRect` to an image blob in the browser. Same-origin or\n * CORS-enabled sources only — a tainted canvas cannot be exported.\n */\nexport async function cropToBlob(\n src: string,\n crop: CropRect,\n { outputWidth, rotation = 0, type = \"image/png\", quality = 0.92 }: CropToBlobOptions = {},\n): Promise<Blob> {\n const image = new Image();\n image.crossOrigin = \"anonymous\";\n image.src = src;\n await image.decode();\n\n // The crop is expressed against the turned picture, so turn it first.\n const quarter = rotation % 180 !== 0;\n const turned = document.createElement(\"canvas\");\n turned.width = quarter ? image.naturalHeight : image.naturalWidth;\n turned.height = quarter ? image.naturalWidth : image.naturalHeight;\n const turnedContext = turned.getContext(\"2d\");\n if (!turnedContext) throw new Error(\"Canvas 2D context unavailable\");\n turnedContext.translate(turned.width / 2, turned.height / 2);\n turnedContext.rotate((rotation * Math.PI) / 180);\n turnedContext.drawImage(image, -image.naturalWidth / 2, -image.naturalHeight / 2);\n\n const width = outputWidth ?? crop.width;\n const height = Math.round((crop.height / crop.width) * width);\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const context = canvas.getContext(\"2d\");\n if (!context) throw new Error(\"Canvas 2D context unavailable\");\n context.drawImage(turned, crop.x, crop.y, crop.width, crop.height, 0, 0, width, height);\n\n return new Promise((resolve, reject) => {\n canvas.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(\"Could not encode the crop\"))),\n type,\n quality,\n );\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["_Fragment","Fragment$1","cropRatios","MIN_ZOOM","REST","ImageCropper","forwardRef","rest","frameRef","useRef","frame","setFrame","useState","natural","setNatural","state","setState","ratio","setRatio","aspect","dragRef","imageRef","prev","chooseRatio","next","onAspectChange","turn","by","adopt","useCallback","img","src","quarter","view","baseScale","scale","maxOffsetX","maxOffsetY","node","measure","observer","clamp","nextScale","limitX","limitY","maxZoom","width","height","onPointerDown","event","onPointerMove","drag","dx","dy","endDrag","nudge","className","ratios","ButtonGroup","Button","option","step","move","rotatable","cropToBlob","image","rotation","turned","turnedContext","outputWidth","crop","canvas","context","blob","resolve","reject","type","quality"],"sources":["../../../src/components/ImageCropper/index.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { Button } from \"../Button\";\nimport { ButtonGroup } from \"../ButtonGroup\";\nimport \"./style.css\";\n\nexport interface CropRect {\n /** Left edge of the crop, in the (rotated) image's own pixels. */\n x: number;\n /** Top edge of the crop, in the (rotated) image's own pixels. */\n y: number;\n width: number;\n height: number;\n}\n\nexport interface CropState {\n /** Pan, in stage pixels, from the centre. */\n offsetX: number;\n offsetY: number;\n /** 1 is \"cover the crop window exactly\". */\n zoom: number;\n /** Quarter turns applied to the picture, clockwise: 0, 90, 180 or 270. */\n rotation: number;\n}\n\n/** One offered output shape. `value` is width / height. */\nexport interface CropRatio {\n label: string;\n value: number;\n}\n\n/** The house set: square, portrait, landscape, wide. */\nexport const cropRatios: CropRatio[] = [\n { label: \"1:1\", value: 1 },\n { label: \"4:5\", value: 4 / 5 },\n { label: \"4:3\", value: 4 / 3 },\n { label: \"16:9\", value: 16 / 9 },\n];\n\nexport interface ImageCropperProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n src: string;\n /** Describes the picture for people who cannot see the stage. */\n alt?: string;\n /** Output shape, width / height. 1 for an avatar, 16 / 9 for a hero. */\n aspect?: number;\n /**\n * Offer the reader a choice of output shapes. Omit it — or pass one ratio —\n * when the shape is fixed by the slot the picture is going into.\n */\n ratios?: CropRatio[];\n /** Fires when the reader picks a different shape. */\n onAspectChange?: (aspect: number) => void;\n /** Highest allowed zoom. Past 3 the result is mush on most uploads. */\n maxZoom?: number;\n /** Offer the quarter-turn controls. */\n rotatable?: boolean;\n /** Fires on every pan, zoom, turn and reset, with the crop in image pixels. */\n onChange?: (crop: CropRect, state: CropState) => void;\n}\n\nconst MIN_ZOOM = 1;\nconst REST: CropState = { offsetX: 0, offsetY: 0, zoom: 1, rotation: 0 };\n\n/**\n * Pan-and-zoom cropping over a fixed frame. The frame never moves — the\n * picture does — and the parts that fall outside it stay visible under a\n * veil, so the reader can see what they are trimming away.\n * Drag with a pointer, or focus the stage and use the arrow keys.\n */\nexport const ImageCropper = forwardRef<HTMLDivElement, ImageCropperProps>(\n function ImageCropper(\n {\n src,\n alt = \"\",\n aspect = 1,\n ratios,\n onAspectChange,\n maxZoom = 3,\n rotatable = true,\n onChange,\n className,\n ...rest\n },\n ref,\n ) {\n const frameRef = useRef<HTMLDivElement | null>(null);\n const [frame, setFrame] = useState({ width: 0, height: 0 });\n const [natural, setNatural] = useState({ width: 0, height: 0 });\n const [state, setState] = useState<CropState>(REST);\n const [ratio, setRatio] = useState(aspect);\n const dragRef = useRef<{ pointerId: number; x: number; y: number } | null>(null);\n const imageRef = useRef<HTMLImageElement | null>(null);\n\n // The prop stays the source of truth when the caller drives the shape.\n useEffect(() => {\n setRatio(aspect);\n setState((prev) => ({ ...REST, rotation: prev.rotation }));\n }, [aspect]);\n\n const chooseRatio = (next: number) => {\n setRatio(next);\n setState((prev) => ({ ...REST, rotation: prev.rotation }));\n onAspectChange?.(next);\n };\n\n const turn = (by: number) =>\n setState((prev) => ({ ...REST, rotation: (prev.rotation + by + 360) % 360 }));\n\n /** Take the picture's own pixels and start from a centred, unzoomed view. */\n const adopt = useCallback((img: HTMLImageElement) => {\n if (!img.naturalWidth) return;\n setNatural({ width: img.naturalWidth, height: img.naturalHeight });\n setState(REST);\n }, []);\n\n // A cached or server-rendered image can already be decoded before React\n // attaches onLoad, and then that event never fires.\n useEffect(() => {\n const img = imageRef.current;\n if (img?.complete) adopt(img);\n }, [adopt, src]);\n\n // After a quarter turn the picture presents its other side to the frame.\n const quarter = state.rotation % 180 !== 0;\n const view = {\n width: quarter ? natural.height : natural.width,\n height: quarter ? natural.width : natural.height,\n };\n\n // The scale at which the image exactly covers the frame; zoom multiplies it.\n const baseScale =\n view.width && frame.width\n ? Math.max(frame.width / view.width, frame.height / view.height)\n : 0;\n const scale = baseScale * state.zoom;\n const maxOffsetX = scale ? Math.max(0, (view.width * scale - frame.width) / 2) : 0;\n const maxOffsetY = scale ? Math.max(0, (view.height * scale - frame.height) / 2) : 0;\n\n useLayoutEffect(() => {\n const node = frameRef.current;\n if (!node) return;\n const measure = () =>\n setFrame({ width: node.clientWidth, height: node.clientHeight });\n measure();\n const observer = new ResizeObserver(measure);\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const clamp = useCallback(\n (next: CropState): CropState => {\n const nextScale = baseScale * next.zoom;\n const limitX = nextScale\n ? Math.max(0, (view.width * nextScale - frame.width) / 2)\n : 0;\n const limitY = nextScale\n ? Math.max(0, (view.height * nextScale - frame.height) / 2)\n : 0;\n return {\n rotation: next.rotation,\n zoom: Math.min(maxZoom, Math.max(MIN_ZOOM, next.zoom)),\n offsetX: Math.min(limitX, Math.max(-limitX, next.offsetX)),\n offsetY: Math.min(limitY, Math.max(-limitY, next.offsetY)),\n };\n },\n [baseScale, maxZoom, view.height, view.width, frame.height, frame.width],\n );\n\n useEffect(() => {\n if (!scale || !frame.width) return;\n const width = frame.width / scale;\n const height = frame.height / scale;\n onChange?.(\n {\n x: Math.round(view.width / 2 - state.offsetX / scale - width / 2),\n y: Math.round(view.height / 2 - state.offsetY / scale - height / 2),\n width: Math.round(width),\n height: Math.round(height),\n },\n state,\n );\n // onChange is intentionally not a dependency: callers pass inline handlers.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scale, frame.width, frame.height, view.width, view.height, state]);\n\n const onPointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (event.button !== 0) return;\n dragRef.current = { pointerId: event.pointerId, x: event.clientX, y: event.clientY };\n event.currentTarget.setPointerCapture(event.pointerId);\n };\n\n const onPointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== event.pointerId) return;\n const dx = event.clientX - drag.x;\n const dy = event.clientY - drag.y;\n dragRef.current = { ...drag, x: event.clientX, y: event.clientY };\n setState((prev) => clamp({ ...prev, offsetX: prev.offsetX + dx, offsetY: prev.offsetY + dy }));\n };\n\n const endDrag = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (dragRef.current?.pointerId !== event.pointerId) return;\n dragRef.current = null;\n event.currentTarget.releasePointerCapture?.(event.pointerId);\n };\n\n const nudge = (dx: number, dy: number) =>\n setState((prev) => clamp({ ...prev, offsetX: prev.offsetX + dx, offsetY: prev.offsetY + dy }));\n\n return (\n <div ref={ref} className={[\"ds-cropper\", className].filter(Boolean).join(\" \")} {...rest}>\n {ratios && ratios.length > 1 && (\n <ButtonGroup aria-label=\"Crop ratio\" className=\"ds-cropper__ratios\">\n {ratios.map((option) => (\n <Button\n key={option.label}\n size=\"sm\"\n variant={option.value === ratio ? \"active\" : \"neutral\"}\n aria-pressed={option.value === ratio}\n onClick={() => chooseRatio(option.value)}\n >\n {option.label}\n </Button>\n ))}\n </ButtonGroup>\n )}\n <div\n role=\"application\"\n aria-label=\"Crop area — drag to reposition, arrow keys to nudge\"\n tabIndex={0}\n className=\"ds-cropper__stage\"\n style={{ \"--cropper-aspect\": String(ratio) } as CSSProperties}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onKeyDown={(event) => {\n const step = event.shiftKey ? 24 : 8;\n const moves: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, -step],\n ArrowDown: [0, step],\n };\n const move = moves[event.key];\n if (!move) return;\n event.preventDefault();\n nudge(move[0], move[1]);\n }}\n >\n <img\n ref={imageRef}\n src={src}\n alt={alt}\n draggable={false}\n className=\"ds-cropper__image\"\n onLoad={(event) => adopt(event.currentTarget)}\n style={{\n inlineSize: natural.width * scale || undefined,\n blockSize: natural.height * scale || undefined,\n transform: `translate(calc(-50% + ${state.offsetX}px), calc(-50% + ${state.offsetY}px)) rotate(${state.rotation}deg)`,\n }}\n />\n {/* The window: everything outside it is veiled, not hidden. */}\n <div className=\"ds-cropper__frame\" ref={frameRef} aria-hidden=\"true\">\n <div className=\"ds-cropper__guides\" />\n </div>\n </div>\n\n <div className=\"ds-cropper__controls\">\n <label className=\"ds-cropper__zoom\">\n <span className=\"ds-cropper__zoom-label\">Zoom</span>\n <input\n type=\"range\"\n min={MIN_ZOOM}\n max={maxZoom}\n step={0.01}\n value={state.zoom}\n className=\"ds-cropper__slider\"\n onChange={(event) =>\n setState((prev) => clamp({ ...prev, zoom: Number(event.target.value) }))\n }\n />\n <span className=\"ds-cropper__value\">{state.zoom.toFixed(2)}×</span>\n </label>\n <ButtonGroup aria-label=\"Crop actions\">\n {rotatable && (\n <>\n <Button\n size=\"sm\"\n iconStart=\"rotate-ccw\"\n aria-label=\"Rotate left\"\n onClick={() => turn(-90)}\n />\n <Button\n size=\"sm\"\n iconStart=\"rotate-cw\"\n aria-label=\"Rotate right\"\n onClick={() => turn(90)}\n />\n </>\n )}\n <Button size=\"sm\" onClick={() => setState(REST)}>\n Reset\n </Button>\n </ButtonGroup>\n </div>\n\n <p className=\"ds-cropper__hint\">\n Drag the picture to reposition it. Nothing is written until you save —{\" \"}\n {maxOffsetX === 0 && maxOffsetY === 0\n ? \"at this zoom the whole picture is in frame.\"\n : \"the veiled edges are what gets trimmed.\"}\n </p>\n </div>\n );\n },\n);\n\nexport interface CropToBlobOptions {\n /** Width of the output in pixels; the height follows the crop's aspect. */\n outputWidth?: number;\n /** Quarter turns applied before cropping — pass `state.rotation`. */\n rotation?: number;\n type?: \"image/png\" | \"image/jpeg\" | \"image/webp\";\n quality?: number;\n}\n\n/**\n * Renders a `CropRect` to an image blob in the browser. Same-origin or\n * CORS-enabled sources only — a tainted canvas cannot be exported.\n */\nexport async function cropToBlob(\n src: string,\n crop: CropRect,\n { outputWidth, rotation = 0, type = \"image/png\", quality = 0.92 }: CropToBlobOptions = {},\n): Promise<Blob> {\n const image = new Image();\n image.crossOrigin = \"anonymous\";\n image.src = src;\n await image.decode();\n\n // The crop is expressed against the turned picture, so turn it first.\n const quarter = rotation % 180 !== 0;\n const turned = document.createElement(\"canvas\");\n turned.width = quarter ? image.naturalHeight : image.naturalWidth;\n turned.height = quarter ? image.naturalWidth : image.naturalHeight;\n const turnedContext = turned.getContext(\"2d\");\n if (!turnedContext) throw new Error(\"Canvas 2D context unavailable\");\n turnedContext.translate(turned.width / 2, turned.height / 2);\n turnedContext.rotate((rotation * Math.PI) / 180);\n turnedContext.drawImage(image, -image.naturalWidth / 2, -image.naturalHeight / 2);\n\n const width = outputWidth ?? crop.width;\n const height = Math.round((crop.height / crop.width) * width);\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const context = canvas.getContext(\"2d\");\n if (!context) throw new Error(\"Canvas 2D context unavailable\");\n context.drawImage(turned, crop.x, crop.y, crop.width, crop.height, 0, 0, width, height);\n\n return new Promise((resolve, reject) => {\n canvas.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(\"Could not encode the crop\"))),\n type,\n quality,\n );\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../Button/index.cjs");let t=require("react"),n=require("react/jsx-runtime"),r=require("react-dom");var i=(0,t.forwardRef)(function({isOpen:i,onClose:a,title:o,description:s,size:c=`md`,footer:l,className:u,children:d,...f},p){let m=(0,t.useRef)(null),h=(0,t.useRef)(a),g=(0,t.useId)(),_=(0,t.useId)();return(0,t.useEffect)(()=>{h.current=a},[a]),(0,t.useEffect)(()=>{if(!i)return;let e=document.activeElement;(m.current?.querySelector(
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../Button/index.cjs");let t=require("react"),n=require("react/jsx-runtime"),r=require("react-dom");var i=(0,t.forwardRef)(function({isOpen:i,onClose:a,title:o,description:s,size:c=`md`,footer:l,className:u,children:d,...f},p){let m=(0,t.useRef)(null),h=(0,t.useRef)(a),g=(0,t.useId)(),_=(0,t.useId)();return(0,t.useEffect)(()=>{h.current=a},[a]),(0,t.useEffect)(()=>{if(!i)return;let e=document.activeElement;(m.current?.querySelector(`:is(button, [href], input, select, textarea, [tabindex]):not(:disabled):not([tabindex='-1'])`)??m.current)?.focus();let t=e=>{if(e.key===`Escape`){h.current();return}if(e.key!==`Tab`)return;let t=Array.from(m.current?.querySelectorAll(`:is(button, [href], input, select, textarea, [tabindex]):not(:disabled):not([tabindex='-1'])`)??[]);if(t.length===0)return;let n=t[0],r=t[t.length-1];e.shiftKey&&document.activeElement===n?(e.preventDefault(),r.focus()):!e.shiftKey&&document.activeElement===r&&(e.preventDefault(),n.focus())};document.addEventListener(`keydown`,t);let n=document.body.style.overflow;return document.body.style.overflow=`hidden`,()=>{document.removeEventListener(`keydown`,t),document.body.style.overflow=n,e?.focus()}},[i]),!i||typeof document>`u`?null:(0,r.createPortal)((0,n.jsx)(`div`,{className:`ds-scrim`,onMouseDown:e=>e.target===e.currentTarget&&h.current(),children:(0,n.jsxs)(`div`,{...f,ref:e=>{m.current=e,typeof p==`function`?p(e):p&&(p.current=e)},role:`dialog`,"aria-modal":`true`,"aria-labelledby":g,"aria-describedby":s?_:void 0,tabIndex:-1,"data-size":c,className:[`ds-modal`,u].filter(Boolean).join(` `),children:[(0,n.jsxs)(`header`,{className:`ds-modal__head`,children:[(0,n.jsxs)(`div`,{className:`ds-modal__titles`,children:[(0,n.jsx)(`h2`,{id:g,className:`ds-modal__title`,children:o}),s&&(0,n.jsx)(`p`,{id:_,className:`ds-modal__description`,children:s})]}),(0,n.jsx)(e.Button,{variant:`simple`,size:`sm`,isIconOnly:!0,iconStart:`x`,"aria-label":`Close`,className:`ds-modal__close`,onClick:()=>h.current()})]}),(0,n.jsx)(`div`,{className:`ds-modal__body`,children:d}),l&&(0,n.jsx)(`footer`,{className:`ds-modal__footer`,children:l})]})}),document.body)});exports.Modal=i;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["forwardRef","useRef","useId","createPortal","Button","require_components_Button_index","react","react_jsx_runtime","react_dom","Modal","rest","panelRef","onCloseRef","onClose","titleId","descriptionId","isOpen","previous","onKeyDown","event","focusable","first","last","overflow","node","ref","description","size","className","title","footer"],"sources":["../../../src/components/Modal/index.tsx"],"sourcesContent":["import { forwardRef, useEffect, useId, useRef, type HTMLAttributes, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Button } from \"../Button\";\nimport \"./style.css\";\n\nexport type ModalSize = \"dialog\" | \"md\" | \"wide\";\n\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n isOpen: boolean;\n /** Escape, the scrim and the close button all call this. */\n onClose: () => void;\n title: string;\n description?: string;\n size?: ModalSize;\n /** Actions, right-aligned. The confirming action goes last. */\n footer?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * A focused task on top of the page. Heavy frame, hairline rules, a quiet\n * footer band — the collection frame, floated. Focus is trapped while open.\n */\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\n { isOpen, onClose, title, description, size = \"md\", footer, className, children, ...rest },\n ref,\n) {\n const panelRef = useRef<HTMLDivElement | null>(null);\n const onCloseRef = useRef(onClose);\n const titleId = useId();\n const descriptionId = useId();\n\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const previous = document.activeElement as HTMLElement | null;\n const initialFocus = panelRef.current?.querySelector<HTMLElement>(\n \"
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["forwardRef","useRef","useId","createPortal","Button","require_components_Button_index","react","react_jsx_runtime","react_dom","Modal","rest","panelRef","onCloseRef","onClose","titleId","descriptionId","isOpen","previous","onKeyDown","event","focusable","first","last","overflow","node","ref","description","size","className","title","footer"],"sources":["../../../src/components/Modal/index.tsx"],"sourcesContent":["import { forwardRef, useEffect, useId, useRef, type HTMLAttributes, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Button } from \"../Button\";\nimport \"./style.css\";\n\nexport type ModalSize = \"dialog\" | \"md\" | \"wide\";\n\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n isOpen: boolean;\n /** Escape, the scrim and the close button all call this. */\n onClose: () => void;\n title: string;\n description?: string;\n size?: ModalSize;\n /** Actions, right-aligned. The confirming action goes last. */\n footer?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * A focused task on top of the page. Heavy frame, hairline rules, a quiet\n * footer band — the collection frame, floated. Focus is trapped while open.\n */\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\n { isOpen, onClose, title, description, size = \"md\", footer, className, children, ...rest },\n ref,\n) {\n const panelRef = useRef<HTMLDivElement | null>(null);\n const onCloseRef = useRef(onClose);\n const titleId = useId();\n const descriptionId = useId();\n\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const previous = document.activeElement as HTMLElement | null;\n const initialFocus = panelRef.current?.querySelector<HTMLElement>(\n \":is(button, [href], input, select, textarea, [tabindex]):not(:disabled):not([tabindex='-1'])\",\n );\n (initialFocus ?? panelRef.current)?.focus();\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onCloseRef.current();\n return;\n }\n if (event.key !== \"Tab\") return;\n const focusable = Array.from(\n panelRef.current?.querySelectorAll<HTMLElement>(\n \":is(button, [href], input, select, textarea, [tabindex]):not(:disabled):not([tabindex='-1'])\",\n ) ?? [],\n );\n if (focusable.length === 0) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n const overflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.body.style.overflow = overflow;\n previous?.focus();\n };\n }, [isOpen]);\n\n if (!isOpen || typeof document === \"undefined\") return null;\n\n return createPortal(\n <div className=\"ds-scrim\" onMouseDown={(event) => event.target === event.currentTarget && onCloseRef.current()}>\n <div\n {...rest}\n ref={(node) => {\n panelRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n tabIndex={-1}\n data-size={size}\n className={[\"ds-modal\", className].filter(Boolean).join(\" \")}\n >\n <header className=\"ds-modal__head\">\n <div className=\"ds-modal__titles\">\n <h2 id={titleId} className=\"ds-modal__title\">\n {title}\n </h2>\n {description && (\n <p id={descriptionId} className=\"ds-modal__description\">\n {description}\n </p>\n )}\n </div>\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label=\"Close\"\n className=\"ds-modal__close\"\n onClick={() => onCloseRef.current()}\n />\n </header>\n <div className=\"ds-modal__body\">{children}</div>\n {footer && <footer className=\"ds-modal__footer\">{footer}</footer>}\n </div>\n </div>,\n document.body,\n );\n});\n"],"mappings":"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"}
|
|
@@ -10,14 +10,14 @@ var c = t(function({ isOpen: t, onClose: c, title: l, description: u, size: d =
|
|
|
10
10
|
}, [c]), n(() => {
|
|
11
11
|
if (!t) return;
|
|
12
12
|
let e = document.activeElement;
|
|
13
|
-
(_.current?.querySelector("
|
|
13
|
+
(_.current?.querySelector(":is(button, [href], input, select, textarea, [tabindex]):not(:disabled):not([tabindex='-1'])") ?? _.current)?.focus();
|
|
14
14
|
let n = (e) => {
|
|
15
15
|
if (e.key === "Escape") {
|
|
16
16
|
v.current();
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
if (e.key !== "Tab") return;
|
|
20
|
-
let t = Array.from(_.current?.querySelectorAll("
|
|
20
|
+
let t = Array.from(_.current?.querySelectorAll(":is(button, [href], input, select, textarea, [tabindex]):not(:disabled):not([tabindex='-1'])") ?? []);
|
|
21
21
|
if (t.length === 0) return;
|
|
22
22
|
let n = t[0], r = t[t.length - 1];
|
|
23
23
|
e.shiftKey && document.activeElement === n ? (e.preventDefault(), r.focus()) : !e.shiftKey && document.activeElement === r && (e.preventDefault(), n.focus());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Modal","forwardRef","rest","panelRef","useRef","onCloseRef","onClose","titleId","useId","descriptionId","useEffect","isOpen","previous","onKeyDown","event","focusable","first","last","overflow","createPortal","node","ref","description","size","className","title","Button","footer"],"sources":["../../../src/components/Modal/index.tsx"],"sourcesContent":["import { forwardRef, useEffect, useId, useRef, type HTMLAttributes, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Button } from \"../Button\";\nimport \"./style.css\";\n\nexport type ModalSize = \"dialog\" | \"md\" | \"wide\";\n\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n isOpen: boolean;\n /** Escape, the scrim and the close button all call this. */\n onClose: () => void;\n title: string;\n description?: string;\n size?: ModalSize;\n /** Actions, right-aligned. The confirming action goes last. */\n footer?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * A focused task on top of the page. Heavy frame, hairline rules, a quiet\n * footer band — the collection frame, floated. Focus is trapped while open.\n */\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\n { isOpen, onClose, title, description, size = \"md\", footer, className, children, ...rest },\n ref,\n) {\n const panelRef = useRef<HTMLDivElement | null>(null);\n const onCloseRef = useRef(onClose);\n const titleId = useId();\n const descriptionId = useId();\n\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const previous = document.activeElement as HTMLElement | null;\n const initialFocus = panelRef.current?.querySelector<HTMLElement>(\n \"
|
|
1
|
+
{"version":3,"file":"index.js","names":["Modal","forwardRef","rest","panelRef","useRef","onCloseRef","onClose","titleId","useId","descriptionId","useEffect","isOpen","previous","onKeyDown","event","focusable","first","last","overflow","createPortal","node","ref","description","size","className","title","Button","footer"],"sources":["../../../src/components/Modal/index.tsx"],"sourcesContent":["import { forwardRef, useEffect, useId, useRef, type HTMLAttributes, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Button } from \"../Button\";\nimport \"./style.css\";\n\nexport type ModalSize = \"dialog\" | \"md\" | \"wide\";\n\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n isOpen: boolean;\n /** Escape, the scrim and the close button all call this. */\n onClose: () => void;\n title: string;\n description?: string;\n size?: ModalSize;\n /** Actions, right-aligned. The confirming action goes last. */\n footer?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * A focused task on top of the page. Heavy frame, hairline rules, a quiet\n * footer band — the collection frame, floated. Focus is trapped while open.\n */\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\n { isOpen, onClose, title, description, size = \"md\", footer, className, children, ...rest },\n ref,\n) {\n const panelRef = useRef<HTMLDivElement | null>(null);\n const onCloseRef = useRef(onClose);\n const titleId = useId();\n const descriptionId = useId();\n\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const previous = document.activeElement as HTMLElement | null;\n const initialFocus = panelRef.current?.querySelector<HTMLElement>(\n \":is(button, [href], input, select, textarea, [tabindex]):not(:disabled):not([tabindex='-1'])\",\n );\n (initialFocus ?? panelRef.current)?.focus();\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onCloseRef.current();\n return;\n }\n if (event.key !== \"Tab\") return;\n const focusable = Array.from(\n panelRef.current?.querySelectorAll<HTMLElement>(\n \":is(button, [href], input, select, textarea, [tabindex]):not(:disabled):not([tabindex='-1'])\",\n ) ?? [],\n );\n if (focusable.length === 0) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n const overflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.body.style.overflow = overflow;\n previous?.focus();\n };\n }, [isOpen]);\n\n if (!isOpen || typeof document === \"undefined\") return null;\n\n return createPortal(\n <div className=\"ds-scrim\" onMouseDown={(event) => event.target === event.currentTarget && onCloseRef.current()}>\n <div\n {...rest}\n ref={(node) => {\n panelRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n tabIndex={-1}\n data-size={size}\n className={[\"ds-modal\", className].filter(Boolean).join(\" \")}\n >\n <header className=\"ds-modal__head\">\n <div className=\"ds-modal__titles\">\n <h2 id={titleId} className=\"ds-modal__title\">\n {title}\n </h2>\n {description && (\n <p id={descriptionId} className=\"ds-modal__description\">\n {description}\n </p>\n )}\n </div>\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"x\"\n aria-label=\"Close\"\n className=\"ds-modal__close\"\n onClick={() => onCloseRef.current()}\n />\n </header>\n <div className=\"ds-modal__body\">{children}</div>\n {footer && <footer className=\"ds-modal__footer\">{footer}</footer>}\n </div>\n </div>,\n document.body,\n );\n});\n"],"mappings":";;;;;AAuBA,IAAaA,IAAQC,EAAuC,SAC1D,EAAE,WAAQ,YAAS,UAAO,gBAAa,UAAO,MAAM,WAAQ,cAAW,aAAU,GAAGC,KACpF,GACA;CACA,IAAMC,IAAWC,EAA8B,IAAI,GAC7CC,IAAaD,EAAOE,CAAO,GAC3BC,IAAUC,EAAM,GAChBC,IAAgBD,EAAM;CAmD5B,OAjDAE,QAAgB;EACd,EAAW,UAAUJ;CACvB,GAAG,CAACA,CAAO,CAAC,GAEZI,QAAgB;EACd,IAAI,CAACC,GAAQ;EAEb,IAAMC,IAAW,SAAS;EAI1B,CAHqBT,EAAS,SAAS,cACrC,8FACF,KACiBA,EAAS,QAAA,EAAU,MAAM;EAE1C,IAAMU,KAAa,MAAyB;GAC1C,IAAIC,EAAM,QAAQ,UAAU;IAC1B,EAAW,QAAQ;IACnB;GACF;GACA,IAAIA,EAAM,QAAQ,OAAO;GACzB,IAAMC,IAAY,MAAM,KACtBZ,EAAS,SAAS,iBAChB,8FACF,KAAK,CAAC,CACR;GACA,IAAIY,EAAU,WAAW,GAAG;GAC5B,IAAMC,IAAQD,EAAU,IAClBE,IAAOF,EAAUA,EAAU,SAAS;GAC1C,AAAID,EAAM,YAAY,SAAS,kBAAkBE,KAC/CF,EAAM,eAAe,GACrBG,EAAK,MAAM,KACF,CAACH,EAAM,YAAY,SAAS,kBAAkBG,MACvDH,EAAM,eAAe,GACrBE,EAAM,MAAM;EAEhB;EAEA,SAAS,iBAAiB,WAAWH,CAAS;EAC9C,IAAMK,IAAW,SAAS,KAAK,MAAM;EAGrC,OAFA,SAAS,KAAK,MAAM,WAAW,gBAElB;GAGX,AAFA,SAAS,oBAAoB,WAAWL,CAAS,GACjD,SAAS,KAAK,MAAM,WAAWK,GAC/BN,GAAU,MAAM;EAClB;CACF,GAAG,CAACD,CAAM,CAAC,GAEP,CAACA,KAAU,OAAO,WAAa,MAAoB,OAEhDQ,EACL,kBAAC,OAAD;EAAK,WAAU;EAAW,cAAc,MAAUL,EAAM,WAAWA,EAAM,iBAAiBT,EAAW,QAAQ;EAC3G,UAAA,kBAAC,OAAD;GACE,GAAIH;GACJ,MAAM,MAAS;IAEb,AADA,EAAS,UAAUkB,GACf,OAAOC,KAAQ,aAAYA,EAAID,CAAI,IAC9BC,MAAK,EAAI,UAAUD;GAC9B;GACA,MAAK;GACL,cAAW;GACX,mBAAiBb;GACjB,oBAAkBe,IAAcb,IAAgB,KAAA;GAChD,UAAU;GACV,aAAWc;GACX,WAAW,CAAC,YAAYC,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;GAb7D,UAAA;IAeE,kBAAC,UAAD;KAAQ,WAAU;KAAlB,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC,MAAD;OAAI,IAAIjB;OAAS,WAAU;OACxB,UAAAkB;MACC,CAAA,GACHH,KACC,kBAAC,KAAD;OAAG,IAAIb;OAAe,WAAU;OAC7B,UAAAa;MACA,CAAA,CAEF;KACL,CAAA,GAAA,kBAACI,GAAD;MACE,SAAQ;MACR,MAAK;MACL,YAAA;MACA,WAAU;MACV,cAAW;MACX,WAAU;MACV,eAAerB,EAAW,QAAQ;KACnC,CAAA,CACK;;IACR,kBAAC,OAAD;KAAK,WAAU;KAAkB;IAAc,CAAA;IAC9CsB,KAAU,kBAAC,UAAD;KAAQ,WAAU;KAAoB,UAAAA;IAAe,CAAA;GAC7D;;CACF,CAAA,GACL,SAAS,IACX;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/RichTextEditor-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require("../Field/index.cjs"),require("../TextField/index.cjs");const e=require("../../chunks/RichTextEditor-DC_0oN1s.cjs");exports.RichTextEditor=e.t;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAS1H,OAAO,EAAuE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACxH,OAAO,oBAAoB,CAAC;AAC5B,OAAO,aAAa,CAAC;AAErB,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,UAAU,yBAAyB;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,uCAAuC;IACvC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;CACjD;AAED,MAAM,MAAM,mBAAmB,GAAG,yBAAyB,GAAG,CAC1D;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GAC7F;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAAE,CACjI,CAAC;AA8JF;;;GAGG;AACH,eAAO,MAAM,cAAc,gHAiK1B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAS1H,OAAO,EAAuE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACxH,OAAO,oBAAoB,CAAC;AAC5B,OAAO,aAAa,CAAC;AAErB,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,UAAU,yBAAyB;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,uCAAuC;IACvC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;CACjD;AAED,MAAM,MAAM,mBAAmB,GAAG,yBAAyB,GAAG,CAC1D;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GAC7F;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAAE,CACjI,CAAC;AA8JF;;;GAGG;AACH,eAAO,MAAM,cAAc,gHAiK1B,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/Icon-CWsA1W83.cjs");let t=require("react"),n=require("react/jsx-runtime");function r(...e){return e.filter(Boolean).join(` `)}var i=(0,t.forwardRef)(function({className:e,children:t,...i},a){return(0,n.jsx)(`div`,{ref:a,className:r(`ds-table-frame`,e),...i,children:t})}),a=(0,t.forwardRef)(function({start:e,end:t,className:i,...a},o){return(0,n.jsxs)(`div`,{ref:o,className:r(`ds-table-toolbar`,i),...a,children:[(0,n.jsx)(`div`,{className:`ds-table-toolbar__group`,children:e}),(0,n.jsx)(`div`,{className:`ds-table-toolbar__group`,children:t})]})}),o=(0,t.forwardRef)(function({
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/Icon-CWsA1W83.cjs");let t=require("react"),n=require("react/jsx-runtime");function r(...e){return e.filter(Boolean).join(` `)}var i=(0,t.forwardRef)(function({className:e,children:t,...i},a){return(0,n.jsx)(`div`,{ref:a,className:r(`ds-table-frame`,e),...i,children:t})}),a=(0,t.forwardRef)(function({start:e,end:t,className:i,...a},o){return(0,n.jsxs)(`div`,{ref:o,className:r(`ds-table-toolbar`,i),...a,children:[(0,n.jsx)(`div`,{className:`ds-table-toolbar__group`,children:e}),(0,n.jsx)(`div`,{className:`ds-table-toolbar__group`,children:t})]})});function o(e){return t.Children.toArray(e).some(e=>(0,t.isValidElement)(e)&&(e.type!==t.Fragment||o(e.props.children)))}var s=(0,t.createContext)({emptyMessage:`No data found.`}),c=(0,t.forwardRef)(function({emptyMessage:e=`No data found.`,isEmpty:t,className:i,children:a,...o},c){return(0,n.jsx)(s.Provider,{value:{emptyMessage:e,isEmpty:t},children:(0,n.jsx)(`div`,{className:`ds-table-frame__scroll`,children:(0,n.jsx)(`table`,{...o,ref:c,className:r(`ds-table`,i),children:a})})})}),l=(0,t.forwardRef)(function({className:e,...t},r){return(0,n.jsx)(`thead`,{ref:r,className:e,...t})}),u=(0,t.forwardRef)(function({className:e,children:r,...i},a){let{emptyMessage:c,isEmpty:l}=(0,t.useContext)(s);return(0,n.jsx)(`tbody`,{ref:a,className:e,...i,children:l??!o(r)?(0,n.jsx)(d,{children:(0,n.jsx)(p,{colSpan:1e3,className:`ds-table__empty-cell`,children:(0,n.jsx)(m,{title:c,role:`status`})})}):r})}),d=(0,t.forwardRef)(function({isSelected:e=!1,isInteractive:t=!1,className:r,...i},a){return(0,n.jsx)(`tr`,{ref:a,"data-selected":e||void 0,"data-interactive":t||void 0,tabIndex:t?0:void 0,className:r,...i})}),f=(0,t.forwardRef)(function({align:e=`start`,width:t=`auto`,className:r,...i},a){return(0,n.jsx)(`th`,{ref:a,scope:`col`,"data-align":e,"data-width":t,className:r,...i})}),p=(0,t.forwardRef)(function({align:e=`start`,width:t=`auto`,emphasis:r=`default`,className:i,...a},o){return(0,n.jsx)(`td`,{ref:o,"data-align":e,"data-width":t,"data-emphasis":r==="default"?void 0:r,className:i,...a})}),m=(0,t.forwardRef)(function({icon:t=`info`,title:i=`No data found.`,description:a,action:o,className:s,...c},l){return(0,n.jsxs)(`div`,{ref:l,className:r(`ds-table-empty`,s),...c,children:[(0,n.jsx)(e.t,{name:t,size:24}),(0,n.jsx)(`span`,{style:{color:`var(--color-text)`,fontWeight:`var(--font-weight-bold)`},children:i}),a&&(0,n.jsx)(`span`,{children:a}),o]})});exports.Table=c,exports.TableBody=u,exports.TableCell=p,exports.TableEmpty=m,exports.TableFrame=i,exports.TableHead=l,exports.TableHeaderCell=f,exports.TableRow=d,exports.TableToolbar=a;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["forwardRef","Icon","require_Icon","react","react_jsx_runtime","cx","parts","TableFrame","rest","className","TableToolbar","start","end","Table","TableHead","TableBody","TableRow","isSelected","isInteractive","TableHeaderCell","align","width","TableCell","emphasis","TableEmpty","icon","title","description","action"],"sources":["../../../src/components/Table/index.tsx"],"sourcesContent":["import {\n forwardRef,\n type HTMLAttributes,\n type ReactNode,\n type TableHTMLAttributes,\n type TdHTMLAttributes,\n type ThHTMLAttributes,\n} from \"react\";\nimport { Icon } from \"../Icon\";\nimport type { IconName } from \"../Icon/icons\";\nimport \"./style.css\";\n\nfunction cx(...parts: (string | undefined | false)[]) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface TableFrameProps extends HTMLAttributes<HTMLDivElement> {\n children?: ReactNode;\n}\n\n/** The 3px collection frame every table, list and board sits inside. */\nexport const TableFrame = forwardRef<HTMLDivElement, TableFrameProps>(function TableFrame(\n { className, children, ...rest },\n ref,\n) {\n return (\n <div ref={ref} className={cx(\"ds-table-frame\", className)} {...rest}>\n {children}\n </div>\n );\n});\n\nexport interface TableToolbarProps extends HTMLAttributes<HTMLDivElement> {\n /** Left side — usually a select-all checkbox, a title and a count badge. */\n start?: ReactNode;\n /** Right side — filters and the one primary action. */\n end?: ReactNode;\n}\n\n/** The band above the rules: selection, title, count, filters, primary action. */\nexport const TableToolbar = forwardRef<HTMLDivElement, TableToolbarProps>(\n function TableToolbar({ start, end, className, ...rest }, ref) {\n return (\n <div ref={ref} className={cx(\"ds-table-toolbar\", className)} {...rest}>\n <div className=\"ds-table-toolbar__group\">{start}</div>\n <div className=\"ds-table-toolbar__group\">{end}</div>\n </div>\n );\n },\n);\n\nexport interface TableProps extends TableHTMLAttributes<HTMLTableElement> {\n children?: ReactNode;\n}\n\n/** The rules layer. Always render it inside a `TableFrame`. */\nexport const Table = forwardRef<HTMLTableElement, TableProps>(function Table(\n { className, children, ...rest },\n ref,\n) {\n return (\n <div className=\"ds-table-frame__scroll\">\n <table ref={ref} className={cx(\"ds-table\", className)} {...rest}>\n {children}\n </table>\n </div>\n );\n});\n\nexport const TableHead = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableHead({ className, ...rest }, ref) {\n return <thead ref={ref} className={className} {...rest} />;\n },\n);\n\nexport const TableBody = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableBody({ className, ...rest }, ref) {\n return <tbody ref={ref} className={className} {...rest} />;\n },\n);\n\nexport interface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {\n /** Paints the soft fill and the solid rail. Never changes the row's size. */\n isSelected?: boolean;\n /** Marks the row clickable: hover fill plus a pointer cursor. */\n isInteractive?: boolean;\n}\n\nexport const TableRow = forwardRef<HTMLTableRowElement, TableRowProps>(function TableRow(\n { isSelected = false, isInteractive = false, className, ...rest },\n ref,\n) {\n return (\n <tr\n ref={ref}\n data-selected={isSelected || undefined}\n data-interactive={isInteractive || undefined}\n tabIndex={isInteractive ? 0 : undefined}\n className={className}\n {...rest}\n />\n );\n});\n\nexport type TableAlign = \"start\" | \"end\";\nexport type TableCellWidth = \"auto\" | \"control\";\n\nexport interface TableHeaderCellProps\n extends Omit<ThHTMLAttributes<HTMLTableCellElement>, \"align\"> {\n align?: TableAlign;\n width?: TableCellWidth;\n}\n\nexport const TableHeaderCell = forwardRef<HTMLTableCellElement, TableHeaderCellProps>(\n function TableHeaderCell({ align = \"start\", width = \"auto\", className, ...rest }, ref) {\n return (\n <th\n ref={ref}\n scope=\"col\"\n data-align={align}\n data-width={width}\n className={className}\n {...rest}\n />\n );\n },\n);\n\nexport type TableCellEmphasis = \"default\" | \"primary\" | \"muted\";\n\nexport interface TableCellProps\n extends Omit<TdHTMLAttributes<HTMLTableCellElement>, \"align\"> {\n align?: TableAlign;\n width?: TableCellWidth;\n /** `primary` is the row's identity cell — one per row, never two. */\n emphasis?: TableCellEmphasis;\n}\n\nexport const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(function TableCell(\n { align = \"start\", width = \"auto\", emphasis = \"default\", className, ...rest },\n ref,\n) {\n return (\n <td\n ref={ref}\n data-align={align}\n data-width={width}\n data-emphasis={emphasis === \"default\" ? undefined : emphasis}\n className={className}\n {...rest}\n />\n );\n});\n\nexport interface TableEmptyProps extends HTMLAttributes<HTMLDivElement> {\n icon?: IconName;\n title: string;\n description?: string;\n /** One action at most — the thing that ends the empty state. */\n action?: ReactNode;\n}\n\n/** What the frame shows when the collection has no rows. */\nexport const TableEmpty = forwardRef<HTMLDivElement, TableEmptyProps>(function TableEmpty(\n { icon = \"info\", title, description, action, className, ...rest },\n ref,\n) {\n return (\n <div ref={ref} className={cx(\"ds-table-empty\", className)} {...rest}>\n <Icon name={icon} size={24} />\n <span style={{ color: \"var(--color-text)\", fontWeight: \"var(--font-weight-bold)\" }}>\n {title}\n </span>\n {description && <span>{description}</span>}\n {action}\n </div>\n );\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["forwardRef","Children","isValidElement","Fragment","createContext","useContext","Icon","require_Icon","react","react_jsx_runtime","cx","parts","TableFrame","rest","className","TableToolbar","start","end","hasBodyContent","children","child","TableContext","Table","TableHead","TableBody","isEmpty","TableRow","TableCell","TableEmpty","emptyMessage","isSelected","isInteractive","TableHeaderCell","align","width","emphasis","icon","title","description","action"],"sources":["../../../src/components/Table/index.tsx"],"sourcesContent":["import {\n Children,\n Fragment,\n createContext,\n forwardRef,\n isValidElement,\n useContext,\n type HTMLAttributes,\n type ReactNode,\n type TableHTMLAttributes,\n type TdHTMLAttributes,\n type ThHTMLAttributes,\n} from \"react\";\nimport { Icon } from \"../Icon\";\nimport type { IconName } from \"../Icon/icons\";\nimport \"./style.css\";\n\nfunction cx(...parts: (string | undefined | false)[]) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface TableFrameProps extends HTMLAttributes<HTMLDivElement> {\n children?: ReactNode;\n}\n\n/** The 3px collection frame every table, list and board sits inside. */\nexport const TableFrame = forwardRef<HTMLDivElement, TableFrameProps>(function TableFrame(\n { className, children, ...rest },\n ref,\n) {\n return (\n <div ref={ref} className={cx(\"ds-table-frame\", className)} {...rest}>\n {children}\n </div>\n );\n});\n\nexport interface TableToolbarProps extends HTMLAttributes<HTMLDivElement> {\n /** Left side — usually a select-all checkbox, a title and a count badge. */\n start?: ReactNode;\n /** Right side — filters and the one primary action. */\n end?: ReactNode;\n}\n\n/** The band above the rules: selection, title, count, filters, primary action. */\nexport const TableToolbar = forwardRef<HTMLDivElement, TableToolbarProps>(\n function TableToolbar({ start, end, className, ...rest }, ref) {\n return (\n <div ref={ref} className={cx(\"ds-table-toolbar\", className)} {...rest}>\n <div className=\"ds-table-toolbar__group\">{start}</div>\n <div className=\"ds-table-toolbar__group\">{end}</div>\n </div>\n );\n },\n);\n\nexport interface TableProps extends TableHTMLAttributes<HTMLTableElement> {\n /** Message shown when a body has no rows. */\n emptyMessage?: string;\n /** Override empty-child detection when rows are rendered by custom components. */\n isEmpty?: boolean;\n children?: ReactNode;\n}\n\nfunction hasBodyContent(children: ReactNode): boolean {\n return Children.toArray(children).some((child) =>\n isValidElement<{ children?: ReactNode }>(child) &&\n (child.type !== Fragment || hasBodyContent(child.props.children)),\n );\n}\n\nconst TableContext = createContext<{\n emptyMessage: string;\n isEmpty?: boolean;\n}>({ emptyMessage: \"No data found.\" });\n\n/** The rules layer. Always render it inside a `TableFrame`. */\nexport const Table = forwardRef<HTMLTableElement, TableProps>(function Table(\n { emptyMessage = \"No data found.\", isEmpty, className, children, ...rest },\n ref,\n) {\n return (\n <TableContext.Provider value={{ emptyMessage, isEmpty }}>\n <div className=\"ds-table-frame__scroll\">\n <table {...rest} ref={ref} className={cx(\"ds-table\", className)}>\n {children}\n </table>\n </div>\n </TableContext.Provider>\n );\n});\n\nexport const TableHead = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableHead({ className, ...rest }, ref) {\n return <thead ref={ref} className={className} {...rest} />;\n },\n);\n\nexport const TableBody = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableBody({ className, children, ...rest }, ref) {\n const { emptyMessage, isEmpty } = useContext(TableContext);\n return (\n <tbody ref={ref} className={className} {...rest}>\n {(isEmpty ?? !hasBodyContent(children)) ? (\n <TableRow>\n {/* HTML's maximum span covers the row without inspecting columns. */}\n <TableCell colSpan={1000} className=\"ds-table__empty-cell\">\n <TableEmpty title={emptyMessage} role=\"status\" />\n </TableCell>\n </TableRow>\n ) : children}\n </tbody>\n );\n },\n);\n\nexport interface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {\n /** Paints the soft fill and the solid rail. Never changes the row's size. */\n isSelected?: boolean;\n /** Marks the row clickable: hover fill plus a pointer cursor. */\n isInteractive?: boolean;\n}\n\nexport const TableRow = forwardRef<HTMLTableRowElement, TableRowProps>(function TableRow(\n { isSelected = false, isInteractive = false, className, ...rest },\n ref,\n) {\n return (\n <tr\n ref={ref}\n data-selected={isSelected || undefined}\n data-interactive={isInteractive || undefined}\n tabIndex={isInteractive ? 0 : undefined}\n className={className}\n {...rest}\n />\n );\n});\n\nexport type TableAlign = \"start\" | \"end\";\nexport type TableCellWidth = \"auto\" | \"control\";\n\nexport interface TableHeaderCellProps\n extends Omit<ThHTMLAttributes<HTMLTableCellElement>, \"align\"> {\n align?: TableAlign;\n width?: TableCellWidth;\n}\n\nexport const TableHeaderCell = forwardRef<HTMLTableCellElement, TableHeaderCellProps>(\n function TableHeaderCell({ align = \"start\", width = \"auto\", className, ...rest }, ref) {\n return (\n <th\n ref={ref}\n scope=\"col\"\n data-align={align}\n data-width={width}\n className={className}\n {...rest}\n />\n );\n },\n);\n\nexport type TableCellEmphasis = \"default\" | \"primary\" | \"muted\";\n\nexport interface TableCellProps\n extends Omit<TdHTMLAttributes<HTMLTableCellElement>, \"align\"> {\n align?: TableAlign;\n width?: TableCellWidth;\n /** `primary` is the row's identity cell — one per row, never two. */\n emphasis?: TableCellEmphasis;\n}\n\nexport const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(function TableCell(\n { align = \"start\", width = \"auto\", emphasis = \"default\", className, ...rest },\n ref,\n) {\n return (\n <td\n ref={ref}\n data-align={align}\n data-width={width}\n data-emphasis={emphasis === \"default\" ? undefined : emphasis}\n className={className}\n {...rest}\n />\n );\n});\n\nexport interface TableEmptyProps extends HTMLAttributes<HTMLDivElement> {\n icon?: IconName;\n title?: string;\n description?: string;\n /** One action at most — the thing that ends the empty state. */\n action?: ReactNode;\n}\n\n/** What the frame shows when the collection has no rows. */\nexport const TableEmpty = forwardRef<HTMLDivElement, TableEmptyProps>(function TableEmpty(\n { icon = \"info\", title = \"No data found.\", description, action, className, ...rest },\n ref,\n) {\n return (\n <div ref={ref} className={cx(\"ds-table-empty\", className)} {...rest}>\n <Icon name={icon} size={24} />\n <span style={{ color: \"var(--color-text)\", fontWeight: \"var(--font-weight-bold)\" }}>\n {title}\n </span>\n {description && <span>{description}</span>}\n {action}\n </div>\n );\n});\n"],"mappings":"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"}
|
|
@@ -14,6 +14,10 @@ export interface TableToolbarProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
14
14
|
/** The band above the rules: selection, title, count, filters, primary action. */
|
|
15
15
|
export declare const TableToolbar: import("react").ForwardRefExoticComponent<TableToolbarProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
16
16
|
export interface TableProps extends TableHTMLAttributes<HTMLTableElement> {
|
|
17
|
+
/** Message shown when a body has no rows. */
|
|
18
|
+
emptyMessage?: string;
|
|
19
|
+
/** Override empty-child detection when rows are rendered by custom components. */
|
|
20
|
+
isEmpty?: boolean;
|
|
17
21
|
children?: ReactNode;
|
|
18
22
|
}
|
|
19
23
|
/** The rules layer. Always render it inside a `TableFrame`. */
|
|
@@ -44,7 +48,7 @@ export interface TableCellProps extends Omit<TdHTMLAttributes<HTMLTableCellEleme
|
|
|
44
48
|
export declare const TableCell: import("react").ForwardRefExoticComponent<TableCellProps & import("react").RefAttributes<HTMLTableCellElement>>;
|
|
45
49
|
export interface TableEmptyProps extends HTMLAttributes<HTMLDivElement> {
|
|
46
50
|
icon?: IconName;
|
|
47
|
-
title
|
|
51
|
+
title?: string;
|
|
48
52
|
description?: string;
|
|
49
53
|
/** One action at most — the thing that ends the empty state. */
|
|
50
54
|
action?: ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../../src/components/Table/index.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../../src/components/Table/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,aAAa,CAAC;AAMrB,MAAM,WAAW,eAAgB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,wEAAwE;AACxE,eAAO,MAAM,UAAU,4GASrB,CAAC;AAEH,MAAM,WAAW,iBAAkB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACvE,4EAA4E;IAC5E,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uDAAuD;IACvD,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED,kFAAkF;AAClF,eAAO,MAAM,YAAY,8GASxB,CAAC;AAEF,MAAM,WAAW,UAAW,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;IACvE,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAcD,+DAA+D;AAC/D,eAAO,MAAM,KAAK,yGAahB,CAAC;AAEH,eAAO,MAAM,SAAS,6IAIrB,CAAC;AAEF,eAAO,MAAM,SAAS,6IAgBrB,CAAC;AAEF,MAAM,WAAW,aAAc,SAAQ,cAAc,CAAC,mBAAmB,CAAC;IACxE,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,QAAQ,+GAcnB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;AACzC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,oBACf,SAAQ,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC7D,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,eAAO,MAAM,eAAe,uHAa3B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC7D,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,eAAO,MAAM,SAAS,iHAcpB,CAAC;AAEH,MAAM,WAAW,eAAgB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACrE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,4DAA4D;AAC5D,eAAO,MAAM,UAAU,4GAcrB,CAAC"}
|
|
@@ -14,6 +14,10 @@ export interface TableToolbarProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
14
14
|
/** The band above the rules: selection, title, count, filters, primary action. */
|
|
15
15
|
export declare const TableToolbar: import("react").ForwardRefExoticComponent<TableToolbarProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
16
16
|
export interface TableProps extends TableHTMLAttributes<HTMLTableElement> {
|
|
17
|
+
/** Message shown when a body has no rows. */
|
|
18
|
+
emptyMessage?: string;
|
|
19
|
+
/** Override empty-child detection when rows are rendered by custom components. */
|
|
20
|
+
isEmpty?: boolean;
|
|
17
21
|
children?: ReactNode;
|
|
18
22
|
}
|
|
19
23
|
/** The rules layer. Always render it inside a `TableFrame`. */
|
|
@@ -44,7 +48,7 @@ export interface TableCellProps extends Omit<TdHTMLAttributes<HTMLTableCellEleme
|
|
|
44
48
|
export declare const TableCell: import("react").ForwardRefExoticComponent<TableCellProps & import("react").RefAttributes<HTMLTableCellElement>>;
|
|
45
49
|
export interface TableEmptyProps extends HTMLAttributes<HTMLDivElement> {
|
|
46
50
|
icon?: IconName;
|
|
47
|
-
title
|
|
51
|
+
title?: string;
|
|
48
52
|
description?: string;
|
|
49
53
|
/** One action at most — the thing that ends the empty state. */
|
|
50
54
|
action?: ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Table/index.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Table/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,aAAa,CAAC;AAMrB,MAAM,WAAW,eAAgB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,wEAAwE;AACxE,eAAO,MAAM,UAAU,4GASrB,CAAC;AAEH,MAAM,WAAW,iBAAkB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACvE,4EAA4E;IAC5E,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uDAAuD;IACvD,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED,kFAAkF;AAClF,eAAO,MAAM,YAAY,8GASxB,CAAC;AAEF,MAAM,WAAW,UAAW,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;IACvE,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAcD,+DAA+D;AAC/D,eAAO,MAAM,KAAK,yGAahB,CAAC;AAEH,eAAO,MAAM,SAAS,6IAIrB,CAAC;AAEF,eAAO,MAAM,SAAS,6IAgBrB,CAAC;AAEF,MAAM,WAAW,aAAc,SAAQ,cAAc,CAAC,mBAAmB,CAAC;IACxE,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,QAAQ,+GAcnB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;AACzC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,oBACf,SAAQ,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC7D,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,eAAO,MAAM,eAAe,uHAa3B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC7D,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,eAAO,MAAM,SAAS,iHAcpB,CAAC;AAEH,MAAM,WAAW,eAAgB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACrE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,4DAA4D;AAC5D,eAAO,MAAM,UAAU,4GAcrB,CAAC"}
|