decantr 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +868 -0
- package/CHANGELOG.md +255 -0
- package/CLAUDE.md +178 -0
- package/LICENSE +21 -0
- package/README.md +229 -0
- package/cli/art.js +127 -0
- package/cli/commands/a11y.js +61 -0
- package/cli/commands/audit.js +225 -0
- package/cli/commands/build.js +38 -0
- package/cli/commands/dev.js +18 -0
- package/cli/commands/doctor.js +197 -0
- package/cli/commands/figma-sync.js +48 -0
- package/cli/commands/figma-tokens.js +55 -0
- package/cli/commands/generate.js +26 -0
- package/cli/commands/init.js +116 -0
- package/cli/commands/lint.js +209 -0
- package/cli/commands/mcp.js +530 -0
- package/cli/commands/migrate.js +175 -0
- package/cli/commands/test.js +38 -0
- package/cli/commands/validate.js +354 -0
- package/cli/index.js +113 -0
- package/package.json +95 -0
- package/reference/atoms.md +517 -0
- package/reference/behaviors.md +384 -0
- package/reference/build-tooling.md +275 -0
- package/reference/color-guidelines.md +965 -0
- package/reference/component-lifecycle.md +137 -0
- package/reference/compound-spacing.md +95 -0
- package/reference/decantation-process.md +499 -0
- package/reference/dev-server-routes.md +93 -0
- package/reference/form-system.md +253 -0
- package/reference/i18n.md +336 -0
- package/reference/icons.md +576 -0
- package/reference/llm-primer.md +953 -0
- package/reference/plugins.md +252 -0
- package/reference/registry-consumption.md +76 -0
- package/reference/router.md +217 -0
- package/reference/shells.md +116 -0
- package/reference/spatial-guidelines.md +541 -0
- package/reference/ssr.md +234 -0
- package/reference/state-data.md +215 -0
- package/reference/state-patterns.md +166 -0
- package/reference/state.md +194 -0
- package/reference/style-system.md +110 -0
- package/reference/tokens.md +460 -0
- package/src/app.js +19 -0
- package/src/chart/_animate.js +266 -0
- package/src/chart/_base.js +109 -0
- package/src/chart/_data.js +209 -0
- package/src/chart/_format.js +106 -0
- package/src/chart/_interact.js +364 -0
- package/src/chart/_palette.js +105 -0
- package/src/chart/_renderer.js +52 -0
- package/src/chart/_scene.js +262 -0
- package/src/chart/_shared.js +371 -0
- package/src/chart/index.js +637 -0
- package/src/chart/layouts/_layout-base.js +328 -0
- package/src/chart/layouts/cartesian.js +148 -0
- package/src/chart/layouts/hierarchy.js +562 -0
- package/src/chart/layouts/polar.js +101 -0
- package/src/chart/renderers/canvas.js +179 -0
- package/src/chart/renderers/svg.js +256 -0
- package/src/chart/renderers/webgpu.js +715 -0
- package/src/chart/types/_type-base.js +26 -0
- package/src/chart/types/area.js +134 -0
- package/src/chart/types/bar.js +173 -0
- package/src/chart/types/box-plot.js +125 -0
- package/src/chart/types/bubble.js +63 -0
- package/src/chart/types/candlestick.js +115 -0
- package/src/chart/types/chord.js +85 -0
- package/src/chart/types/combination.js +108 -0
- package/src/chart/types/funnel.js +68 -0
- package/src/chart/types/gauge.js +163 -0
- package/src/chart/types/heatmap.js +98 -0
- package/src/chart/types/histogram.js +71 -0
- package/src/chart/types/line.js +111 -0
- package/src/chart/types/org-chart.js +93 -0
- package/src/chart/types/pie.js +81 -0
- package/src/chart/types/radar.js +96 -0
- package/src/chart/types/radial.js +68 -0
- package/src/chart/types/range-area.js +55 -0
- package/src/chart/types/range-bar.js +61 -0
- package/src/chart/types/sankey.js +73 -0
- package/src/chart/types/scatter.js +66 -0
- package/src/chart/types/sparkline.js +81 -0
- package/src/chart/types/sunburst.js +69 -0
- package/src/chart/types/swimlane.js +88 -0
- package/src/chart/types/treemap.js +62 -0
- package/src/chart/types/waterfall.js +100 -0
- package/src/components/_base.js +1658 -0
- package/src/components/_behaviors.js +1140 -0
- package/src/components/_primitives.js +534 -0
- package/src/components/_qr-encoder.js +539 -0
- package/src/components/accordion.js +207 -0
- package/src/components/affix.js +62 -0
- package/src/components/alert-dialog.js +75 -0
- package/src/components/alert.js +47 -0
- package/src/components/aspect-ratio.js +24 -0
- package/src/components/avatar-group.js +55 -0
- package/src/components/avatar.js +38 -0
- package/src/components/back-top.js +75 -0
- package/src/components/badge.js +74 -0
- package/src/components/banner.js +68 -0
- package/src/components/breadcrumb.js +162 -0
- package/src/components/button.js +115 -0
- package/src/components/calendar.js +131 -0
- package/src/components/card.js +192 -0
- package/src/components/carousel.js +98 -0
- package/src/components/cascader.js +261 -0
- package/src/components/checkbox.js +80 -0
- package/src/components/chip.js +81 -0
- package/src/components/code-block.js +82 -0
- package/src/components/collapsible.js +50 -0
- package/src/components/color-palette.js +438 -0
- package/src/components/color-picker.js +314 -0
- package/src/components/combobox.js +181 -0
- package/src/components/command.js +174 -0
- package/src/components/comment.js +206 -0
- package/src/components/context-menu.js +76 -0
- package/src/components/data-table.js +724 -0
- package/src/components/date-picker.js +217 -0
- package/src/components/date-range-picker.js +244 -0
- package/src/components/datetime-picker.js +271 -0
- package/src/components/descriptions.js +68 -0
- package/src/components/drawer.js +179 -0
- package/src/components/dropdown.js +88 -0
- package/src/components/empty.js +41 -0
- package/src/components/float-button.js +90 -0
- package/src/components/form.js +106 -0
- package/src/components/hover-card.js +49 -0
- package/src/components/icon.js +87 -0
- package/src/components/image.js +97 -0
- package/src/components/index.js +117 -0
- package/src/components/input-group.js +75 -0
- package/src/components/input-number.js +155 -0
- package/src/components/input-otp.js +178 -0
- package/src/components/input.js +91 -0
- package/src/components/kbd.js +36 -0
- package/src/components/label.js +25 -0
- package/src/components/list.js +118 -0
- package/src/components/masked-input.js +236 -0
- package/src/components/mentions.js +165 -0
- package/src/components/menu.js +259 -0
- package/src/components/message.js +80 -0
- package/src/components/modal.js +147 -0
- package/src/components/navigation-menu.js +166 -0
- package/src/components/notification.js +84 -0
- package/src/components/pagination.js +104 -0
- package/src/components/placeholder.js +132 -0
- package/src/components/popconfirm.js +70 -0
- package/src/components/popover.js +58 -0
- package/src/components/progress.js +61 -0
- package/src/components/qrcode.js +251 -0
- package/src/components/radiogroup.js +120 -0
- package/src/components/range-slider.js +176 -0
- package/src/components/rate.js +186 -0
- package/src/components/resizable.js +83 -0
- package/src/components/result.js +57 -0
- package/src/components/scroll-area.js +43 -0
- package/src/components/segmented.js +97 -0
- package/src/components/select.js +165 -0
- package/src/components/separator.js +31 -0
- package/src/components/shell.js +407 -0
- package/src/components/skeleton.js +39 -0
- package/src/components/slider.js +141 -0
- package/src/components/sortable-list.js +176 -0
- package/src/components/space.js +42 -0
- package/src/components/spinner.js +112 -0
- package/src/components/splitter.js +147 -0
- package/src/components/statistic.js +136 -0
- package/src/components/steps.js +99 -0
- package/src/components/switch.js +95 -0
- package/src/components/table.js +44 -0
- package/src/components/tabs.js +216 -0
- package/src/components/tag.js +115 -0
- package/src/components/textarea.js +82 -0
- package/src/components/time-picker.js +153 -0
- package/src/components/time-range-picker.js +170 -0
- package/src/components/timeline.js +226 -0
- package/src/components/toast.js +71 -0
- package/src/components/toggle.js +213 -0
- package/src/components/tooltip.js +57 -0
- package/src/components/tour.js +159 -0
- package/src/components/transfer.js +163 -0
- package/src/components/tree-select.js +274 -0
- package/src/components/tree.js +141 -0
- package/src/components/typography.js +136 -0
- package/src/components/upload.js +118 -0
- package/src/components/visually-hidden.js +20 -0
- package/src/components/watermark.js +124 -0
- package/src/core/index.js +539 -0
- package/src/core/lifecycle.js +69 -0
- package/src/css/atoms.js +651 -0
- package/src/css/components.js +940 -0
- package/src/css/derive.js +1296 -0
- package/src/css/index.js +265 -0
- package/src/css/runtime.js +268 -0
- package/src/css/styles/addons/bioluminescent.js +93 -0
- package/src/css/styles/addons/clay.js +70 -0
- package/src/css/styles/addons/clean.js +57 -0
- package/src/css/styles/addons/command-center.js +143 -0
- package/src/css/styles/addons/dopamine.js +83 -0
- package/src/css/styles/addons/editorial.js +80 -0
- package/src/css/styles/addons/glassmorphism.js +99 -0
- package/src/css/styles/addons/liquid-glass.js +105 -0
- package/src/css/styles/addons/prismatic.js +100 -0
- package/src/css/styles/addons/retro.js +63 -0
- package/src/css/styles/auradecantism.js +96 -0
- package/src/css/theme-registry.js +444 -0
- package/src/data/entity.js +281 -0
- package/src/data/index.js +13 -0
- package/src/data/persist.js +225 -0
- package/src/data/query.js +839 -0
- package/src/data/realtime.js +299 -0
- package/src/data/url.js +177 -0
- package/src/data/worker.js +134 -0
- package/src/explorer/archetypes.js +243 -0
- package/src/explorer/atoms.js +228 -0
- package/src/explorer/charts.js +497 -0
- package/src/explorer/components.js +129 -0
- package/src/explorer/foundations.js +949 -0
- package/src/explorer/icons.js +178 -0
- package/src/explorer/patterns.js +247 -0
- package/src/explorer/recipes.js +194 -0
- package/src/explorer/shared/pattern-examples.js +1337 -0
- package/src/explorer/shared/showcase-renderer.js +958 -0
- package/src/explorer/shared/spec-table.js +41 -0
- package/src/explorer/shared/usage-links.js +87 -0
- package/src/explorer/shell-config.js +10 -0
- package/src/explorer/shells.js +551 -0
- package/src/explorer/styles.js +161 -0
- package/src/explorer/tokens.js +262 -0
- package/src/explorer/tools.js +525 -0
- package/src/form/index.js +804 -0
- package/src/i18n/index.js +251 -0
- package/src/icons/essential.js +479 -0
- package/src/icons/index.js +53 -0
- package/src/plugins/index.js +282 -0
- package/src/registry/archetypes/content-site.json +71 -0
- package/src/registry/archetypes/docs-explorer.json +23 -0
- package/src/registry/archetypes/ecommerce.json +104 -0
- package/src/registry/archetypes/financial-dashboard.json +77 -0
- package/src/registry/archetypes/index.json +41 -0
- package/src/registry/archetypes/portfolio.json +82 -0
- package/src/registry/archetypes/recipe-community.json +159 -0
- package/src/registry/archetypes/saas-dashboard.json +86 -0
- package/src/registry/architect/cross-cutting.json +45 -0
- package/src/registry/architect/domains/ecommerce.json +294 -0
- package/src/registry/architect/domains/financial-services.json +302 -0
- package/src/registry/architect/index.json +26 -0
- package/src/registry/architect/traits.json +379 -0
- package/src/registry/atoms.json +16 -0
- package/src/registry/chart-showcase.json +160 -0
- package/src/registry/chart.json +136 -0
- package/src/registry/components.json +8616 -0
- package/src/registry/core.json +216 -0
- package/src/registry/css.json +319 -0
- package/src/registry/data.json +135 -0
- package/src/registry/foundations.json +11 -0
- package/src/registry/icons.json +463 -0
- package/src/registry/index.json +101 -0
- package/src/registry/patterns/activity-feed.json +37 -0
- package/src/registry/patterns/article-content.json +27 -0
- package/src/registry/patterns/auth-form.json +37 -0
- package/src/registry/patterns/author-card.json +20 -0
- package/src/registry/patterns/card-grid.json +127 -0
- package/src/registry/patterns/category-nav.json +26 -0
- package/src/registry/patterns/chart-grid.json +36 -0
- package/src/registry/patterns/chat-interface.json +37 -0
- package/src/registry/patterns/checklist-card.json +55 -0
- package/src/registry/patterns/comparison-panel.json +27 -0
- package/src/registry/patterns/component-showcase.json +24 -0
- package/src/registry/patterns/contact-form.json +31 -0
- package/src/registry/patterns/cta-section.json +20 -0
- package/src/registry/patterns/data-table.json +37 -0
- package/src/registry/patterns/detail-header.json +83 -0
- package/src/registry/patterns/detail-panel.json +27 -0
- package/src/registry/patterns/explorer-shell.json +22 -0
- package/src/registry/patterns/filter-bar.json +33 -0
- package/src/registry/patterns/filter-sidebar.json +27 -0
- package/src/registry/patterns/form-sections.json +110 -0
- package/src/registry/patterns/goal-tracker.json +27 -0
- package/src/registry/patterns/hero.json +107 -0
- package/src/registry/patterns/index.json +47 -0
- package/src/registry/patterns/kpi-grid.json +36 -0
- package/src/registry/patterns/media-gallery.json +20 -0
- package/src/registry/patterns/order-history.json +20 -0
- package/src/registry/patterns/pagination.json +19 -0
- package/src/registry/patterns/photo-to-recipe.json +36 -0
- package/src/registry/patterns/pipeline-tracker.json +28 -0
- package/src/registry/patterns/post-list.json +27 -0
- package/src/registry/patterns/pricing-table.json +32 -0
- package/src/registry/patterns/scorecard.json +28 -0
- package/src/registry/patterns/search-bar.json +20 -0
- package/src/registry/patterns/specimen-grid.json +19 -0
- package/src/registry/patterns/stat-card.json +55 -0
- package/src/registry/patterns/stats-bar.json +55 -0
- package/src/registry/patterns/steps-card.json +55 -0
- package/src/registry/patterns/table-of-contents.json +19 -0
- package/src/registry/patterns/testimonials.json +21 -0
- package/src/registry/patterns/timeline.json +27 -0
- package/src/registry/patterns/token-inspector.json +21 -0
- package/src/registry/patterns/wizard.json +27 -0
- package/src/registry/recipe-auradecantism.json +69 -0
- package/src/registry/recipe-clean.json +65 -0
- package/src/registry/recipe-command-center.json +78 -0
- package/src/registry/router.json +73 -0
- package/src/registry/schema/README.md +197 -0
- package/src/registry/skeletons.json +259 -0
- package/src/registry/state.json +137 -0
- package/src/registry/tokens.json +40 -0
- package/src/router/hash.js +17 -0
- package/src/router/history.js +18 -0
- package/src/router/index.js +598 -0
- package/src/ssr/index.js +922 -0
- package/src/state/arrays.js +181 -0
- package/src/state/devtools.js +647 -0
- package/src/state/index.js +498 -0
- package/src/state/middleware.js +288 -0
- package/src/state/scheduler.js +206 -0
- package/src/state/store.js +300 -0
- package/src/tags/index.js +19 -0
- package/src/tannins/auth.js +396 -0
- package/src/test/dom.js +352 -0
- package/src/test/index.js +62 -0
- package/src/test/state.js +306 -0
- package/tools/a11y-audit.js +487 -0
- package/tools/analyzer.js +315 -0
- package/tools/audit.js +706 -0
- package/tools/builder.js +1422 -0
- package/tools/css-extract.js +188 -0
- package/tools/dev-server.js +316 -0
- package/tools/dts-gen.js +1260 -0
- package/tools/figma-components.js +329 -0
- package/tools/figma-patterns.js +516 -0
- package/tools/figma-plugin/code.js +453 -0
- package/tools/figma-plugin/manifest.json +14 -0
- package/tools/figma-plugin/ui.html +268 -0
- package/tools/figma-render.js +293 -0
- package/tools/figma-tokens.js +712 -0
- package/tools/figma-upload.js +318 -0
- package/tools/generate.js +738 -0
- package/tools/icons.js +133 -0
- package/tools/init-templates.js +265 -0
- package/tools/install-hooks.sh +5 -0
- package/tools/migrations/0.5.0.js +53 -0
- package/tools/migrations/0.6.0.js +95 -0
- package/tools/minify.js +170 -0
- package/tools/pre-commit +4 -0
- package/tools/registry.js +662 -0
- package/tools/reset-playground.js +61 -0
- package/tools/starter-templates/content-site/app.js +49 -0
- package/tools/starter-templates/content-site/essence.js +19 -0
- package/tools/starter-templates/content-site/pages.js +31 -0
- package/tools/starter-templates/ecommerce/app.js +50 -0
- package/tools/starter-templates/ecommerce/essence.js +19 -0
- package/tools/starter-templates/ecommerce/pages.js +31 -0
- package/tools/starter-templates/landing-page/app.js +38 -0
- package/tools/starter-templates/landing-page/essence.js +18 -0
- package/tools/starter-templates/landing-page/pages.js +21 -0
- package/tools/starter-templates/portfolio/app.js +45 -0
- package/tools/starter-templates/portfolio/essence.js +19 -0
- package/tools/starter-templates/portfolio/pages.js +33 -0
- package/tools/starter-templates/saas-dashboard/app.js +70 -0
- package/tools/starter-templates/saas-dashboard/essence.js +19 -0
- package/tools/starter-templates/saas-dashboard/pages.js +31 -0
- package/tools/verify-pack.js +203 -0
- package/types/chart.d.ts +77 -0
- package/types/components.d.ts +587 -0
- package/types/core.d.ts +89 -0
- package/types/css.d.ts +149 -0
- package/types/data.d.ts +238 -0
- package/types/form.d.ts +164 -0
- package/types/i18n.d.ts +51 -0
- package/types/icons.d.ts +27 -0
- package/types/index.d.ts +13 -0
- package/types/router.d.ts +116 -0
- package/types/ssr.d.ts +102 -0
- package/types/state.d.ts +83 -0
- package/types/tags.d.ts +62 -0
- package/types/tannins.d.ts +63 -0
- package/types/test.d.ts +48 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Placeholder — Branded visual placeholder for images, avatars, and icons.
|
|
3
|
+
*
|
|
4
|
+
* @module decantr/components/placeholder
|
|
5
|
+
*/
|
|
6
|
+
import { h } from '../core/index.js';
|
|
7
|
+
import { injectBase, cx } from './_base.js';
|
|
8
|
+
|
|
9
|
+
const NS = 'http://www.w3.org/2000/svg';
|
|
10
|
+
|
|
11
|
+
// Logo paths from logo.svg (decantr potion bottle — 27 paths)
|
|
12
|
+
const LOGO_VIEWBOX = '0 0 658 658';
|
|
13
|
+
const LOGO_PATHS = [
|
|
14
|
+
'M364.635 304.958C383.4 303.623 408.998 304.372 428.081 304.414L533.593 304.512L605.189 304.289C631.047 304.093 665.412 300.467 687.08 316.546C698.787 325.238 708.647 345.863 708.932 360.912C710.071 421.027 718.9 465.751 642.923 472.687L643.516 560.565C643.474 591.103 640.373 638.157 648.93 666.205C657.107 693.009 700.931 707.583 724.027 719.602C823.321 771.272 899.712 870.011 934.19 975.048C971.553 1090.89 961.208 1216.85 905.444 1325.04C849.119 1435.97 757.775 1508.95 640.603 1547.14C595.28 1560.61 548.183 1567.16 500.903 1566.58C389.557 1565.46 277.816 1515.23 200.117 1435.93C114.887 1348.26 67.9814 1230.32 69.7232 1108.05C71.3131 956.687 147.116 824.649 271.118 740.514C281.684 732.873 292.536 726.704 304.031 720.58C330.245 706.606 372.509 694.161 379.167 660.701C384.199 635.403 382.06 606.476 381.913 580.627L381.629 472.096C323.616 469.568 310.295 436.765 310.816 384.492C311.221 343.991 320.238 314.419 364.635 304.958ZM428.731 439.339C430.59 498.952 427.476 560.225 429.093 619.913C430.455 670.223 419.951 718.191 369.831 741.325C317.938 765.277 279.286 787.034 238.007 827.712C161.69 903.532 118.545 1006.52 118.028 1114.09C116.122 1402.3 406.962 1603.33 671.72 1484.47C717.376 1463.98 758.679 1435.55 793.676 1399.76C868.57 1322.82 909.545 1219.09 907.451 1111.74C907.09 976.687 838.683 850.917 725.509 777.23C692.575 755.507 655.926 744.696 626.845 717.108C588.416 680.65 597.019 620.908 597.108 571.668L597.125 438.303L575.677 438.445C558.867 438.438 435.027 437.088 428.731 439.339Z',
|
|
15
|
+
'M529.791 699.472C572.855 722.194 602.492 751.681 616.943 799.225C631.127 846.686 626.135 897.817 603.036 941.635C589.315 965.592 581.63 977.253 560.121 995.779L702.761 1077.92L702.489 1118.3C735.6 1120.63 769.752 1118.39 803.226 1118.47C818.331 1118.5 870.912 1114.55 880.986 1128.1C890.765 1141.26 880.65 1184.44 877.757 1200.47C871.936 1228.2 859.506 1264.01 846.51 1289.02C828.737 1323.26 807.713 1355.54 780.35 1382.94C706.553 1456.77 616.532 1497.16 511.109 1498.41C488.311 1498.68 453.02 1495.52 431.063 1488.88L418.503 1485.41C379.361 1474 342.22 1456.61 308.396 1433.85C265.393 1406.88 232.882 1373.36 204.703 1331.48C213.727 1320.34 222.343 1309.42 232.174 1298.96C253.659 1274.02 290.721 1244.48 318.673 1226.97C313.594 1185.39 311.297 1160.97 312.076 1119.2C313.474 1108.11 314.084 1095.82 315.682 1084.47C327.252 1002.26 364.961 969.756 426.256 923.05C513.487 848.496 526.64 813.429 529.791 699.472Z',
|
|
16
|
+
'M232.174 1298.96C253.659 1274.02 290.721 1244.48 318.673 1226.97C320.268 1244.86 321.365 1266.88 336.12 1279.59C345.382 1287.57 357.651 1286.76 365.081 1276.65C371.644 1267.72 372.616 1261.09 372.371 1250.19C412.626 1274.43 452.562 1299.2 492.17 1324.48C503.157 1317.54 528.848 1300.63 539.443 1295.82C542.449 1302.62 550.278 1313.49 554.861 1319.97C574.388 1347.58 584.819 1364.27 590.753 1397.73C625.581 1384.24 662.857 1367.17 687.474 1338.13C700.49 1338.73 714.725 1338.39 727.285 1341.91C746.131 1347.2 771.107 1365.54 780.35 1382.94C706.553 1456.77 616.532 1497.16 511.109 1498.41C488.311 1498.68 453.02 1495.52 431.063 1488.88L418.503 1485.41C379.361 1474 342.22 1456.61 308.396 1433.85C265.393 1406.88 232.882 1373.36 204.703 1331.48C213.727 1320.34 222.343 1309.42 232.174 1298.96Z',
|
|
17
|
+
'M687.474 1338.13C700.49 1338.73 714.725 1338.39 727.285 1341.91C746.131 1347.2 771.107 1365.54 780.35 1382.94C706.553 1456.77 616.532 1497.16 511.109 1498.41C488.311 1498.68 453.02 1495.52 431.063 1488.88L418.503 1485.41C418.62 1485.03 418.74 1484.65 418.861 1484.28L419.502 1482.41C421.271 1477.16 420.997 1476.35 425.22 1473.1C418.826 1449.64 423.495 1431.47 428.248 1408.34C492.971 1419.84 528.786 1414.86 590.753 1397.73C625.581 1384.24 662.857 1367.17 687.474 1338.13Z',
|
|
18
|
+
'M418.503 1485.41C418.62 1485.03 418.74 1484.65 418.861 1484.28L419.502 1482.41C421.271 1477.16 420.997 1476.35 425.22 1473.1L431.063 1488.88L418.503 1485.41Z',
|
|
19
|
+
'M340.414 1385.59C382.881 1349.05 384.214 1399.56 428.248 1408.34C423.495 1431.47 418.826 1449.64 425.22 1473.1C420.997 1476.35 421.271 1477.16 419.502 1482.41L418.861 1484.28C418.74 1484.65 418.62 1485.03 418.503 1485.41C379.361 1474 342.22 1456.61 308.396 1433.85C311.642 1431.26 317.036 1414.61 320.855 1409.2C326.889 1400.67 333.579 1393.39 340.414 1385.59Z',
|
|
20
|
+
'M204.703 1331.48C213.727 1320.34 222.343 1309.42 232.174 1298.96C260.648 1357.97 280.684 1362.02 340.414 1385.59C333.579 1393.39 326.889 1400.67 320.855 1409.2C317.036 1414.61 311.642 1431.26 308.396 1433.85C265.393 1406.88 232.882 1373.36 204.703 1331.48Z',
|
|
21
|
+
'M529.791 699.472C572.855 722.194 602.492 751.681 616.943 799.225C631.127 846.686 626.135 897.817 603.036 941.635C589.315 965.592 581.63 977.253 560.121 995.779L558.357 995.076C542.463 1010.98 500.455 1026.41 489.254 1038.38C469.375 1053.95 447.976 1066.66 426.619 1080.16C412.489 1089.1 390.963 1104.82 375.767 1111.02C367.94 1127.69 370.27 1171.84 370.72 1191.81C371 1204.11 369.64 1242.05 372.371 1250.19C372.616 1261.09 371.644 1267.72 365.081 1276.65C357.651 1286.76 345.382 1287.57 336.12 1279.59C321.365 1266.88 320.268 1244.86 318.673 1226.97C313.594 1185.39 311.297 1160.97 312.076 1119.2C313.474 1108.11 314.084 1095.82 315.682 1084.47C327.252 1002.26 364.961 969.756 426.256 923.05C513.487 848.496 526.64 813.429 529.791 699.472Z',
|
|
22
|
+
'M529.791 699.472C572.855 722.194 602.492 751.681 616.943 799.225C631.127 846.686 626.135 897.817 603.036 941.635C576.312 918.006 551.28 924.27 519.085 923.753C500.146 923.449 439.833 929.951 426.256 923.05C513.487 848.496 526.64 813.429 529.791 699.472Z',
|
|
23
|
+
'M524.352 975.496C533.455 981.687 548.784 990.036 558.357 995.076C542.463 1010.98 500.455 1026.41 489.254 1038.38C469.375 1053.95 447.976 1066.66 426.619 1080.16C412.489 1089.1 390.963 1104.82 375.767 1111.02C390.86 1079.92 451.281 1035.51 479.656 1012.76C494.708 1000.52 509.609 988.101 524.352 975.496Z',
|
|
24
|
+
'M702.489 1118.3C735.6 1120.63 769.752 1118.39 803.226 1118.47C818.331 1118.5 870.912 1114.55 880.986 1128.1C890.765 1141.26 880.65 1184.44 877.757 1200.47C871.936 1228.2 859.506 1264.01 846.51 1289.02C828.737 1323.26 807.713 1355.54 780.35 1382.94C771.107 1365.54 746.131 1347.2 727.285 1341.91C714.725 1338.39 700.49 1338.73 687.474 1338.13C705.073 1298.97 701.945 1271.9 701.587 1230.01C701.448 1193.04 701.526 1156.07 701.827 1119.1L702.489 1118.3Z',
|
|
25
|
+
'M701.587 1230.01C718.498 1216.37 733.3 1208.25 756.256 1210.99C785.443 1214.47 808.6 1230.24 826.912 1252.68C836.089 1263.93 839.21 1279.29 846.51 1289.02C828.737 1323.26 807.713 1355.54 780.35 1382.94C771.107 1365.54 746.131 1347.2 727.285 1341.91C714.725 1338.39 700.49 1338.73 687.474 1338.13C705.073 1298.97 701.945 1271.9 701.587 1230.01Z',
|
|
26
|
+
'M608.771 1120.31C624.599 1122.51 684.395 1120.34 701.827 1119.1C701.526 1156.07 701.448 1193.04 701.587 1230.01C701.945 1271.9 705.073 1298.97 687.474 1338.13C662.857 1367.17 625.581 1384.24 590.753 1397.73C584.819 1364.27 574.388 1347.58 554.861 1319.97C550.278 1313.49 542.449 1302.62 539.443 1295.82C561.081 1280.97 586.282 1265.98 608.653 1251.71C608.573 1209.11 607.475 1162.49 608.771 1120.31Z',
|
|
27
|
+
'M558.357 995.076L560.121 995.779L702.761 1077.92L702.489 1118.3L701.827 1119.1C684.395 1120.34 624.599 1122.51 608.771 1120.31C608.509 1116 607.742 1110.85 603.729 1108.45C565.484 1085.61 527.135 1061.75 489.254 1038.38C500.455 1026.41 542.463 1010.98 558.357 995.076Z',
|
|
28
|
+
'M492.309 1081.1C515.518 1095.02 555.312 1116.19 575.542 1130.05C574.063 1152.13 573.276 1208.56 574.874 1231.87C546.709 1247.44 521.87 1266.52 492.88 1281.24L478.404 1272.91C455.249 1259.43 424.414 1240.94 402.959 1225.24L402.744 1141.5C427.038 1121.95 465.222 1098.91 492.309 1081.1Z',
|
|
29
|
+
'M402.744 1141.5C468.818 1164.86 514.516 1182.27 482.175 1263.65C480.94 1266.74 479.683 1269.83 478.404 1272.91C455.249 1259.43 424.414 1240.94 402.959 1225.24L402.744 1141.5Z',
|
|
30
|
+
'M139.11 1118.64C196.763 1119.16 254.42 1119.35 312.076 1119.2C311.297 1160.97 313.594 1185.39 318.673 1226.97C290.721 1244.48 253.659 1274.02 232.174 1298.96C222.343 1309.42 213.727 1320.34 204.703 1331.48C158.16 1257.44 143.539 1205.72 139.11 1118.64Z',
|
|
31
|
+
'M377.592 801.738C379.74 804.164 383.898 814.821 386.467 818.953C398.27 837.935 414.622 846.73 434.684 854.508C402.369 869.273 392.682 879.014 379.456 911.815L378.927 912.477C376.504 913.074 376.769 911.176 375.882 908.091C367.227 877.946 349.912 868.803 324.435 854.545C354.755 839.574 363.672 833.116 377.592 801.738Z',
|
|
32
|
+
'M796.151 1004.36C815.577 1004.01 831.724 1019.25 832.485 1038.67C833.245 1058.09 818.34 1074.55 798.943 1075.71C786.033 1076.49 773.711 1070.22 766.734 1059.33C759.757 1048.44 759.218 1034.62 765.32 1023.22C771.423 1011.81 783.218 1004.6 796.151 1004.36Z',
|
|
33
|
+
'M523.735 557.858C525.802 559.698 528.95 565.215 530.633 567.731C542.14 584.924 544.827 586.879 562.75 595.439C543.673 606.152 537.132 611.934 525.094 629.999C523.005 629.098 516.224 618.83 513.781 615.959C505.107 605.755 498.108 601.316 486.153 596.002C505.937 584.013 512.103 577.952 523.735 557.858Z',
|
|
34
|
+
'M655.951 946.382C661.622 938.736 664.547 933.477 669.226 925.118C679.655 942.458 684.782 949.244 702.31 960.192C690.666 967.26 686.169 969.507 677.626 980.237C675.054 984.541 672.536 989.191 670.061 993.581C658.952 974.94 657.288 971.655 638.398 960.871C644.829 955.927 649.863 951.748 655.951 946.382Z',
|
|
35
|
+
'M638.398 960.871C644.829 955.927 649.863 951.748 655.951 946.382C659.758 947.769 663.476 949.146 667.337 950.393C673.079 961.875 673.4 972.635 677.626 980.237C675.054 984.541 672.536 989.191 670.061 993.581C658.952 974.94 657.288 971.655 638.398 960.871Z',
|
|
36
|
+
'M578.318 338.798C594.442 336.549 616.786 337.529 633.151 338.727C668.449 341.316 669.001 375.8 667.413 402.506C664.949 444.001 628.602 438.418 597.125 438.303L575.677 438.445C558.867 438.438 435.027 437.088 428.731 439.339C424.98 437.184 404.003 437.901 398.442 437.534C366.94 435.464 358.969 424.775 357.626 394.755C356.306 365.241 357.271 342.237 393.292 339.074C412.675 337.374 431.536 339.062 450.783 339.079C493.294 339.322 535.807 339.229 578.318 338.798Z',
|
|
37
|
+
'M578.318 338.798C594.442 336.549 616.786 337.529 633.151 338.727C668.449 341.316 669.001 375.8 667.413 402.506C664.949 444.001 628.602 438.418 597.125 438.303L575.677 438.445C572.774 434.8 566.77 433.308 562.399 431.578C534.778 419.537 516.268 405.563 530.65 374.083C541.902 349.462 580.599 357.235 586.351 345.378C584.178 341.056 583.399 341.752 578.318 338.798Z',
|
|
38
|
+
'M591.554 117.162C612.323 116.856 622.068 115.317 635.424 133.329C636.752 161.1 636.603 190.293 636.448 218.182C636.282 247.862 636.13 265.79 601.177 265.954L567.446 265.922C517.231 267.088 458.623 264.077 409.899 266.618C398.52 263.697 386.328 256.921 385.674 244.285C383.846 209.063 383.785 167.862 385.63 132.883C387.166 130.541 388.829 128.287 390.615 126.131C396.533 119.071 402.041 118.644 410.649 118.044C470.771 116.684 531.334 118.211 591.554 117.162Z',
|
|
39
|
+
'M591.554 117.162C612.323 116.856 622.068 115.317 635.424 133.329C636.752 161.1 636.603 190.293 636.448 218.182C636.282 247.862 636.13 265.79 601.177 265.954L567.446 265.922C558.254 256.103 543.242 249.831 534.862 238.567C525.136 225.495 519.293 207.535 522.25 191.358C529.315 152.707 561.402 157.403 586.358 139.583L587.71 138.601C587.698 131.709 586.275 121.562 591.554 117.162Z',
|
|
40
|
+
'M385.63 132.883C387.166 130.541 388.829 128.287 390.615 126.131C396.533 119.071 402.041 118.644 410.649 118.044C411.947 133.365 409.179 167.715 408.87 185.307C408.407 211.381 410.747 241.539 409.899 266.618C398.52 263.697 386.328 256.921 385.674 244.285C383.846 209.063 383.785 167.862 385.63 132.883Z',
|
|
41
|
+
];
|
|
42
|
+
// Shared transform for all paths (from logo.svg)
|
|
43
|
+
const PATH_TX = 'matrix(0.408203 0 0 0.408442 0 -0.000244141)';
|
|
44
|
+
|
|
45
|
+
function createWatermark() {
|
|
46
|
+
const svg = document.createElementNS(NS, 'svg');
|
|
47
|
+
svg.setAttribute('viewBox', LOGO_VIEWBOX);
|
|
48
|
+
svg.setAttribute('aria-hidden', 'true');
|
|
49
|
+
// Outer flip group (mirrors the original SVG structure)
|
|
50
|
+
const flip = document.createElementNS(NS, 'g');
|
|
51
|
+
flip.setAttribute('transform', 'scale(-1,1) translate(-658,0)');
|
|
52
|
+
// Inner offset group
|
|
53
|
+
const offset = document.createElementNS(NS, 'g');
|
|
54
|
+
offset.setAttribute('transform', 'translate(120,-15)');
|
|
55
|
+
offset.setAttribute('fill', 'currentColor');
|
|
56
|
+
for (const d of LOGO_PATHS) {
|
|
57
|
+
const path = document.createElementNS(NS, 'path');
|
|
58
|
+
path.setAttribute('transform', PATH_TX);
|
|
59
|
+
path.setAttribute('d', d);
|
|
60
|
+
offset.appendChild(path);
|
|
61
|
+
}
|
|
62
|
+
flip.appendChild(offset);
|
|
63
|
+
svg.appendChild(flip);
|
|
64
|
+
return svg;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Object} [props]
|
|
69
|
+
* @param {'image'|'avatar'|'icon'} [props.variant='image']
|
|
70
|
+
* @param {string} [props.aspectRatio] - CSS aspect-ratio override
|
|
71
|
+
* @param {string} [props.width] - Explicit width
|
|
72
|
+
* @param {string} [props.height] - Explicit height
|
|
73
|
+
* @param {string} [props.label] - Text overlay
|
|
74
|
+
* @param {Node} [props.icon] - Custom icon replacing logo watermark
|
|
75
|
+
* @param {boolean} [props.animate=false] - Shimmer animation
|
|
76
|
+
* @param {string} [props.class]
|
|
77
|
+
* @param {...Node} children
|
|
78
|
+
* @returns {HTMLElement}
|
|
79
|
+
*/
|
|
80
|
+
export function Placeholder(props = {}, ...children) {
|
|
81
|
+
injectBase();
|
|
82
|
+
const {
|
|
83
|
+
variant = 'image',
|
|
84
|
+
aspectRatio,
|
|
85
|
+
width,
|
|
86
|
+
height,
|
|
87
|
+
label,
|
|
88
|
+
icon: customIcon,
|
|
89
|
+
animate = false,
|
|
90
|
+
class: cls,
|
|
91
|
+
...rest
|
|
92
|
+
} = props;
|
|
93
|
+
|
|
94
|
+
const variantClass = variant !== 'image' ? `d-placeholder-${variant}` : '';
|
|
95
|
+
const animateClass = animate ? 'd-placeholder-animate' : '';
|
|
96
|
+
const container = h('div', {
|
|
97
|
+
class: cx('d-placeholder', variantClass, animateClass, cls),
|
|
98
|
+
role: 'img',
|
|
99
|
+
'aria-label': label || `${variant} placeholder`,
|
|
100
|
+
...rest,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Apply per-instance dimensions
|
|
104
|
+
if (width) container.style.width = width;
|
|
105
|
+
if (height) container.style.height = height;
|
|
106
|
+
if (aspectRatio) container.style.aspectRatio = aspectRatio;
|
|
107
|
+
|
|
108
|
+
// Watermark layer
|
|
109
|
+
const wmLayer = h('div', { class: 'd-placeholder-watermark' });
|
|
110
|
+
if (customIcon && customIcon.nodeType) {
|
|
111
|
+
wmLayer.appendChild(customIcon);
|
|
112
|
+
} else {
|
|
113
|
+
wmLayer.appendChild(createWatermark());
|
|
114
|
+
}
|
|
115
|
+
container.appendChild(wmLayer);
|
|
116
|
+
|
|
117
|
+
// Label
|
|
118
|
+
if (label) {
|
|
119
|
+
container.appendChild(h('span', { class: 'd-placeholder-label' }, label));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Children
|
|
123
|
+
for (const child of children) {
|
|
124
|
+
if (child && child.nodeType) {
|
|
125
|
+
const wrapper = h('div', { class: 'd-placeholder-content' });
|
|
126
|
+
wrapper.appendChild(child);
|
|
127
|
+
container.appendChild(wrapper);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return container;
|
|
132
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Popconfirm — Confirmation popover attached to a trigger element.
|
|
3
|
+
* Uses createOverlay behavior for positioning.
|
|
4
|
+
*
|
|
5
|
+
* @module decantr/components/popconfirm
|
|
6
|
+
*/
|
|
7
|
+
import { onDestroy } from '../core/index.js';
|
|
8
|
+
import { tags } from '../tags/index.js';
|
|
9
|
+
import { injectBase, cx } from './_base.js';
|
|
10
|
+
import { createOverlay } from './_behaviors.js';
|
|
11
|
+
|
|
12
|
+
const { div, span, button: buttonTag } = tags;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object} [props]
|
|
16
|
+
* @param {string} [props.title='Are you sure?']
|
|
17
|
+
* @param {string} [props.description]
|
|
18
|
+
* @param {Function} [props.onConfirm]
|
|
19
|
+
* @param {Function} [props.onCancel]
|
|
20
|
+
* @param {string} [props.confirmText='Yes']
|
|
21
|
+
* @param {string} [props.cancelText='No']
|
|
22
|
+
* @param {Node} [props.icon]
|
|
23
|
+
* @param {'top'|'bottom'|'left'|'right'} [props.position='top']
|
|
24
|
+
* @param {Function} props.trigger - Returns trigger element
|
|
25
|
+
* @param {string} [props.class]
|
|
26
|
+
* @returns {HTMLElement}
|
|
27
|
+
*/
|
|
28
|
+
export function Popconfirm(props = {}) {
|
|
29
|
+
injectBase();
|
|
30
|
+
const {
|
|
31
|
+
title = 'Are you sure?', description, onConfirm, onCancel,
|
|
32
|
+
confirmText = 'Yes', cancelText = 'No', icon, position = 'top',
|
|
33
|
+
trigger, class: cls
|
|
34
|
+
} = props;
|
|
35
|
+
|
|
36
|
+
const triggerEl = typeof trigger === 'function' ? trigger() : buttonTag({ type: 'button' }, 'Click');
|
|
37
|
+
|
|
38
|
+
const cancelBtn = buttonTag({ type: 'button', class: 'd-btn d-btn-sm d-btn-outline' }, cancelText);
|
|
39
|
+
const confirmBtn = buttonTag({ type: 'button', class: 'd-btn d-btn-sm d-btn-primary' }, confirmText);
|
|
40
|
+
|
|
41
|
+
const body = div({ class: 'd-popconfirm-body' });
|
|
42
|
+
if (icon) body.appendChild(span({ class: 'd-popconfirm-icon' }, typeof icon === 'string' ? icon : icon));
|
|
43
|
+
const textWrap = div({ class: 'd-popconfirm-text' });
|
|
44
|
+
textWrap.appendChild(div({ class: 'd-popconfirm-title' }, title));
|
|
45
|
+
if (description) textWrap.appendChild(div({ class: 'd-popconfirm-desc' }, description));
|
|
46
|
+
body.appendChild(textWrap);
|
|
47
|
+
|
|
48
|
+
const footer = div({ class: 'd-popconfirm-footer' }, cancelBtn, confirmBtn);
|
|
49
|
+
|
|
50
|
+
const content = div({
|
|
51
|
+
class: cx('d-popconfirm', `d-popover-${position}`, cls)
|
|
52
|
+
}, body, footer);
|
|
53
|
+
|
|
54
|
+
const wrap = div({ class: 'd-popconfirm-wrap' }, triggerEl, content);
|
|
55
|
+
|
|
56
|
+
const overlay = createOverlay(triggerEl, content, {
|
|
57
|
+
trigger: 'click',
|
|
58
|
+
closeOnEscape: true,
|
|
59
|
+
closeOnOutside: true
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
cancelBtn.addEventListener('click', () => { overlay.close(); if (onCancel) onCancel(); });
|
|
63
|
+
confirmBtn.addEventListener('click', () => { overlay.close(); if (onConfirm) onConfirm(); });
|
|
64
|
+
|
|
65
|
+
onDestroy(() => {
|
|
66
|
+
overlay.destroy();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return wrap;
|
|
70
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Popover — Floating content panel attached to a trigger element.
|
|
3
|
+
* Uses createOverlay behavior for show/hide, click-outside, escape.
|
|
4
|
+
*
|
|
5
|
+
* @module decantr/components/popover
|
|
6
|
+
*/
|
|
7
|
+
import { onDestroy } from '../core/index.js';
|
|
8
|
+
import { tags } from '../tags/index.js';
|
|
9
|
+
import { injectBase, cx } from './_base.js';
|
|
10
|
+
import { createOverlay } from './_behaviors.js';
|
|
11
|
+
|
|
12
|
+
const { div } = tags;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object} [props]
|
|
16
|
+
* @param {Function} [props.trigger] — Function returning trigger element
|
|
17
|
+
* @param {string} [props.position] — 'top'|'bottom'|'left'|'right' (default: 'bottom')
|
|
18
|
+
* @param {string} [props.align] — 'start'|'center'|'end' (default: 'center')
|
|
19
|
+
* @param {string} [props.class]
|
|
20
|
+
* @returns {HTMLElement}
|
|
21
|
+
*/
|
|
22
|
+
export function Popover(props = {}, ...children) {
|
|
23
|
+
injectBase();
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
trigger,
|
|
27
|
+
position = 'bottom',
|
|
28
|
+
align = 'center',
|
|
29
|
+
class: cls
|
|
30
|
+
} = props;
|
|
31
|
+
|
|
32
|
+
const content = div({
|
|
33
|
+
class: cx('d-popover-content', `d-popover-${position}`, align !== 'center' && `d-popover-align-${align}`, cls),
|
|
34
|
+
role: 'dialog'
|
|
35
|
+
}, ...children);
|
|
36
|
+
|
|
37
|
+
const wrap = div({ class: 'd-popover' });
|
|
38
|
+
|
|
39
|
+
const triggerEl = typeof trigger === 'function' ? trigger() : tags.button({ type: 'button' }, 'Open');
|
|
40
|
+
triggerEl.setAttribute('aria-haspopup', 'dialog');
|
|
41
|
+
triggerEl.setAttribute('aria-expanded', 'false');
|
|
42
|
+
wrap.appendChild(triggerEl);
|
|
43
|
+
wrap.appendChild(content);
|
|
44
|
+
|
|
45
|
+
const overlay = createOverlay(triggerEl, content, {
|
|
46
|
+
trigger: 'click',
|
|
47
|
+
closeOnEscape: true,
|
|
48
|
+
closeOnOutside: true,
|
|
49
|
+
onOpen: () => wrap.classList.add('d-popover-open'),
|
|
50
|
+
onClose: () => wrap.classList.remove('d-popover-open')
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
onDestroy(() => {
|
|
54
|
+
overlay.destroy();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return wrap;
|
|
58
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { h } from '../core/index.js';
|
|
2
|
+
import { createEffect } from '../state/index.js';
|
|
3
|
+
import { injectBase, cx } from './_base.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Object} [props]
|
|
7
|
+
* @param {number|Function} [props.value] - Current value (0-100 or 0-max)
|
|
8
|
+
* @param {number} [props.max] - Maximum value (default: 100)
|
|
9
|
+
* @param {string} [props.label]
|
|
10
|
+
* @param {string} [props.variant] - primary|success|warning|error
|
|
11
|
+
* @param {string} [props.size] - sm|md|lg (default: base 8px)
|
|
12
|
+
* @param {boolean} [props.striped]
|
|
13
|
+
* @param {boolean} [props.animated]
|
|
14
|
+
* @param {string} [props.class]
|
|
15
|
+
* @returns {HTMLElement}
|
|
16
|
+
*/
|
|
17
|
+
export function Progress(props = {}) {
|
|
18
|
+
injectBase();
|
|
19
|
+
|
|
20
|
+
const { value, max = 100, label, variant, size, striped, animated, class: cls } = props;
|
|
21
|
+
|
|
22
|
+
const progressClass = cx(
|
|
23
|
+
'd-progress',
|
|
24
|
+
size && `d-progress-${size}`,
|
|
25
|
+
variant && `d-progress-${variant}`,
|
|
26
|
+
striped && 'd-progress-striped',
|
|
27
|
+
animated && 'd-progress-animated'
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const bar = h('div', { class: 'd-progress-bar', role: 'progressbar', 'aria-valuemin': '0', 'aria-valuemax': String(max) });
|
|
31
|
+
const progress = h('div', { class: progressClass }, bar);
|
|
32
|
+
|
|
33
|
+
// For md/lg sizes, label goes inside the progress bar; otherwise outside
|
|
34
|
+
const labelInside = size === 'md' || size === 'lg';
|
|
35
|
+
let labelEl = null;
|
|
36
|
+
if (label) {
|
|
37
|
+
labelEl = h('span', { class: 'd-progress-label' }, label);
|
|
38
|
+
if (labelInside) {
|
|
39
|
+
progress.appendChild(labelEl);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const wrap = h('div', { class: cx('d-progress-wrap', cls) }, progress);
|
|
44
|
+
if (label && !labelInside) {
|
|
45
|
+
wrap.appendChild(labelEl);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function updateBar(val) {
|
|
49
|
+
const pct = Math.min(Math.max((val / max) * 100, 0), 100);
|
|
50
|
+
bar.style.width = pct + '%';
|
|
51
|
+
bar.setAttribute('aria-valuenow', String(val));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (typeof value === 'function') {
|
|
55
|
+
createEffect(() => updateBar(value()));
|
|
56
|
+
} else {
|
|
57
|
+
updateBar(value || 0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return wrap;
|
|
61
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QRCode — QR code generator with canvas/SVG rendering and status overlays.
|
|
3
|
+
*
|
|
4
|
+
* @module decantr/components/qrcode
|
|
5
|
+
*/
|
|
6
|
+
import { h } from '../core/index.js';
|
|
7
|
+
import { createEffect } from '../state/index.js';
|
|
8
|
+
import { onMount, onDestroy } from '../core/index.js';
|
|
9
|
+
import { injectBase, cx, resolve } from './_base.js';
|
|
10
|
+
import { encodeQR } from './_qr-encoder.js';
|
|
11
|
+
import { Spinner } from './spinner.js';
|
|
12
|
+
import { icon } from './icon.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object} [props]
|
|
16
|
+
* @param {string|Function} [props.value=''] - Text to encode (reactive)
|
|
17
|
+
* @param {number} [props.size=160] - Pixel dimensions
|
|
18
|
+
* @param {string} [props.color] - Module color (default: resolved --d-fg)
|
|
19
|
+
* @param {string} [props.bgColor] - Background color (default: resolved --d-bg)
|
|
20
|
+
* @param {'canvas'|'svg'} [props.type='canvas'] - Render mode
|
|
21
|
+
* @param {'L'|'M'|'Q'|'H'} [props.level='M'] - Error correction level
|
|
22
|
+
* @param {string} [props.icon] - Center logo URL
|
|
23
|
+
* @param {number} [props.iconSize=40] - Logo size
|
|
24
|
+
* @param {boolean} [props.bordered=true] - Card border
|
|
25
|
+
* @param {string|Function} [props.status] - 'active'|'loading'|'expired'|'scanned' (reactive)
|
|
26
|
+
* @param {Function} [props.onRefresh] - Expired refresh callback
|
|
27
|
+
* @param {number} [props.padding=12] - Quiet zone padding
|
|
28
|
+
* @param {string} [props.class]
|
|
29
|
+
* @returns {HTMLElement}
|
|
30
|
+
*/
|
|
31
|
+
export function QRCode(props = {}) {
|
|
32
|
+
injectBase();
|
|
33
|
+
const {
|
|
34
|
+
value = '', size = 160, color, bgColor,
|
|
35
|
+
type = 'canvas', level = 'M',
|
|
36
|
+
icon: iconUrl, iconSize = 40, bordered = true,
|
|
37
|
+
status, onRefresh, padding = 12,
|
|
38
|
+
class: cls
|
|
39
|
+
} = props;
|
|
40
|
+
|
|
41
|
+
const container = h('div', {
|
|
42
|
+
class: cx('d-qrcode',
|
|
43
|
+
bordered && 'd-qrcode-bordered',
|
|
44
|
+
cls
|
|
45
|
+
)
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
let renderEl = null;
|
|
49
|
+
let statusOverlay = null;
|
|
50
|
+
let resolvedFg = null;
|
|
51
|
+
let resolvedBg = null;
|
|
52
|
+
|
|
53
|
+
function resolveColors() {
|
|
54
|
+
if (color && bgColor) {
|
|
55
|
+
resolvedFg = color;
|
|
56
|
+
resolvedBg = bgColor;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const computed = typeof getComputedStyle === 'function' ? getComputedStyle(container) : null;
|
|
60
|
+
resolvedFg = color || (computed ? computed.getPropertyValue('--d-fg').trim() : '#000') || '#000';
|
|
61
|
+
resolvedBg = bgColor || (computed ? computed.getPropertyValue('--d-bg').trim() : '#fff') || '#fff';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function render(data) {
|
|
65
|
+
if (!data) return;
|
|
66
|
+
|
|
67
|
+
let qr;
|
|
68
|
+
try {
|
|
69
|
+
qr = encodeQR(data, level);
|
|
70
|
+
} catch {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Remove old render element
|
|
75
|
+
if (renderEl && renderEl.parentNode) renderEl.remove();
|
|
76
|
+
|
|
77
|
+
if (type === 'svg') {
|
|
78
|
+
renderEl = renderSVG(qr, size, resolvedFg, resolvedBg, padding);
|
|
79
|
+
} else {
|
|
80
|
+
renderEl = renderCanvas(qr, size, resolvedFg, resolvedBg, padding);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Insert before status overlay or at end
|
|
84
|
+
if (statusOverlay && statusOverlay.parentNode) {
|
|
85
|
+
container.insertBefore(renderEl, statusOverlay);
|
|
86
|
+
} else {
|
|
87
|
+
container.appendChild(renderEl);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Icon overlay
|
|
91
|
+
if (iconUrl) {
|
|
92
|
+
let iconEl = container.querySelector('.d-qrcode-icon');
|
|
93
|
+
if (!iconEl) {
|
|
94
|
+
iconEl = h('img', {
|
|
95
|
+
class: 'd-qrcode-icon',
|
|
96
|
+
src: iconUrl,
|
|
97
|
+
width: String(iconSize),
|
|
98
|
+
height: String(iconSize),
|
|
99
|
+
alt: ''
|
|
100
|
+
});
|
|
101
|
+
container.appendChild(iconEl);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Status overlay
|
|
107
|
+
function updateStatus(s) {
|
|
108
|
+
// Remove existing status classes
|
|
109
|
+
container.classList.remove('d-qrcode-expired', 'd-qrcode-loading', 'd-qrcode-scanned');
|
|
110
|
+
if (statusOverlay) { statusOverlay.remove(); statusOverlay = null; }
|
|
111
|
+
|
|
112
|
+
if (!s || s === 'active') return;
|
|
113
|
+
|
|
114
|
+
container.classList.add(`d-qrcode-${s}`);
|
|
115
|
+
statusOverlay = h('div', { class: 'd-qrcode-status' });
|
|
116
|
+
|
|
117
|
+
if (s === 'loading') {
|
|
118
|
+
statusOverlay.appendChild(Spinner({ size: 'lg' }));
|
|
119
|
+
} else if (s === 'expired') {
|
|
120
|
+
const refreshBtn = h('button', {
|
|
121
|
+
class: 'd-btn d-btn-sm d-btn-primary',
|
|
122
|
+
type: 'button'
|
|
123
|
+
});
|
|
124
|
+
try { refreshBtn.appendChild(icon('refresh-cw', { size: '16' })); } catch {}
|
|
125
|
+
refreshBtn.appendChild(document.createTextNode(' Refresh'));
|
|
126
|
+
if (onRefresh) refreshBtn.addEventListener('click', onRefresh);
|
|
127
|
+
statusOverlay.appendChild(refreshBtn);
|
|
128
|
+
} else if (s === 'scanned') {
|
|
129
|
+
try {
|
|
130
|
+
statusOverlay.appendChild(icon('check', { size: '48', class: 'd-qrcode-check' }));
|
|
131
|
+
} catch {
|
|
132
|
+
statusOverlay.appendChild(h('span', null, '✓'));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
container.appendChild(statusOverlay);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Use requestAnimationFrame to resolve CSS custom properties after mount
|
|
140
|
+
if (typeof requestAnimationFrame === 'function') {
|
|
141
|
+
requestAnimationFrame(() => {
|
|
142
|
+
resolveColors();
|
|
143
|
+
const val = typeof value === 'function' ? value() : value;
|
|
144
|
+
if (val) render(val);
|
|
145
|
+
const st = typeof status === 'function' ? status() : status;
|
|
146
|
+
if (st) updateStatus(st);
|
|
147
|
+
});
|
|
148
|
+
} else {
|
|
149
|
+
// Test/SSR env — resolve immediately
|
|
150
|
+
resolveColors();
|
|
151
|
+
const val = typeof value === 'function' ? value() : value;
|
|
152
|
+
if (val) render(val);
|
|
153
|
+
const st = typeof status === 'function' ? status() : status;
|
|
154
|
+
if (st) updateStatus(st);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Reactive value
|
|
158
|
+
if (typeof value === 'function') {
|
|
159
|
+
createEffect(() => {
|
|
160
|
+
const val = value();
|
|
161
|
+
resolveColors();
|
|
162
|
+
render(val);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Reactive status
|
|
167
|
+
if (typeof status === 'function') {
|
|
168
|
+
createEffect(() => updateStatus(status()));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return container;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Render QR code to a canvas element.
|
|
176
|
+
*/
|
|
177
|
+
function renderCanvas(qr, size, fg, bg, padding) {
|
|
178
|
+
const canvas = h('canvas');
|
|
179
|
+
canvas.width = size;
|
|
180
|
+
canvas.height = size;
|
|
181
|
+
|
|
182
|
+
const ctx = canvas.getContext('2d');
|
|
183
|
+
if (!ctx) return canvas;
|
|
184
|
+
|
|
185
|
+
const moduleCount = qr.size;
|
|
186
|
+
const drawSize = size - padding * 2;
|
|
187
|
+
const cellSize = drawSize / moduleCount;
|
|
188
|
+
|
|
189
|
+
ctx.fillStyle = bg;
|
|
190
|
+
ctx.fillRect(0, 0, size, size);
|
|
191
|
+
|
|
192
|
+
ctx.fillStyle = fg;
|
|
193
|
+
for (let r = 0; r < moduleCount; r++) {
|
|
194
|
+
for (let c = 0; c < moduleCount; c++) {
|
|
195
|
+
if (qr.modules[r][c]) {
|
|
196
|
+
ctx.fillRect(
|
|
197
|
+
padding + c * cellSize,
|
|
198
|
+
padding + r * cellSize,
|
|
199
|
+
cellSize + 0.5,
|
|
200
|
+
cellSize + 0.5
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return canvas;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Render QR code as SVG element.
|
|
211
|
+
*/
|
|
212
|
+
function renderSVG(qr, size, fg, bg, padding) {
|
|
213
|
+
const ns = 'http://www.w3.org/2000/svg';
|
|
214
|
+
const svg = document.createElementNS(ns, 'svg');
|
|
215
|
+
svg.setAttribute('viewBox', `0 0 ${size} ${size}`);
|
|
216
|
+
svg.setAttribute('width', String(size));
|
|
217
|
+
svg.setAttribute('height', String(size));
|
|
218
|
+
svg.setAttribute('xmlns', ns);
|
|
219
|
+
|
|
220
|
+
// Background
|
|
221
|
+
const bgRect = document.createElementNS(ns, 'rect');
|
|
222
|
+
bgRect.setAttribute('width', String(size));
|
|
223
|
+
bgRect.setAttribute('height', String(size));
|
|
224
|
+
bgRect.setAttribute('fill', bg);
|
|
225
|
+
svg.appendChild(bgRect);
|
|
226
|
+
|
|
227
|
+
const moduleCount = qr.size;
|
|
228
|
+
const drawSize = size - padding * 2;
|
|
229
|
+
const cellSize = drawSize / moduleCount;
|
|
230
|
+
|
|
231
|
+
// Build a single path for all modules (much more efficient than individual rects)
|
|
232
|
+
let d = '';
|
|
233
|
+
for (let r = 0; r < moduleCount; r++) {
|
|
234
|
+
for (let c = 0; c < moduleCount; c++) {
|
|
235
|
+
if (qr.modules[r][c]) {
|
|
236
|
+
const x = padding + c * cellSize;
|
|
237
|
+
const y = padding + r * cellSize;
|
|
238
|
+
d += `M${x},${y}h${cellSize}v${cellSize}h${-cellSize}z`;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (d) {
|
|
244
|
+
const path = document.createElementNS(ns, 'path');
|
|
245
|
+
path.setAttribute('d', d);
|
|
246
|
+
path.setAttribute('fill', fg);
|
|
247
|
+
svg.appendChild(path);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return svg;
|
|
251
|
+
}
|