@trdrs/quickcharts 2.4.0 → 4.0.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +326 -25
  3. package/dist/adapters/rest.d.ts +1 -1
  4. package/dist/{ar-KSXQ2USS.js → ar-FXZ5QJUR.js} +206 -56
  5. package/dist/ar-FXZ5QJUR.js.map +1 -0
  6. package/dist/{assets-M5emOz5c.d.ts → assets-Gg-UquDA.d.ts} +285 -61
  7. package/dist/{ca_ES-JG4FM55E.js → ca_ES-3WVKFBIF.js} +206 -56
  8. package/dist/ca_ES-3WVKFBIF.js.map +1 -0
  9. package/dist/chunk-C4MEVUNK.js +11449 -0
  10. package/dist/chunk-C4MEVUNK.js.map +1 -0
  11. package/dist/{de-VSW2LHNF.js → de-V72Q3OI7.js} +206 -56
  12. package/dist/de-V72Q3OI7.js.map +1 -0
  13. package/dist/drawings.d.ts +24 -13
  14. package/dist/drawings.js +5 -1
  15. package/dist/{es-5ZXIPVOB.js → es-CNQ3OJ6E.js} +206 -56
  16. package/dist/es-CNQ3OJ6E.js.map +1 -0
  17. package/dist/feature-manifest.json +94 -11
  18. package/dist/{fr-4F6DAWGD.js → fr-5WQBCGR4.js} +206 -56
  19. package/dist/fr-5WQBCGR4.js.map +1 -0
  20. package/dist/{he_IL-B7PBQUEV.js → he_IL-WXKA77UE.js} +206 -56
  21. package/dist/he_IL-WXKA77UE.js.map +1 -0
  22. package/dist/{id_ID-CYJRMXPC.js → id_ID-XPBAYSWK.js} +206 -56
  23. package/dist/id_ID-XPBAYSWK.js.map +1 -0
  24. package/dist/index.d.ts +1834 -1671
  25. package/dist/index.js +5405 -2619
  26. package/dist/index.js.map +1 -1
  27. package/dist/{it-KTX4SG5P.js → it-DR2EBNWX.js} +206 -56
  28. package/dist/it-DR2EBNWX.js.map +1 -0
  29. package/dist/{ja-V7OURU5D.js → ja-URB2CPXO.js} +206 -56
  30. package/dist/ja-URB2CPXO.js.map +1 -0
  31. package/dist/{ko-2RNEBYVE.js → ko-OE47NYVP.js} +206 -56
  32. package/dist/ko-OE47NYVP.js.map +1 -0
  33. package/dist/{ms_MY-EY235E7Q.js → ms_MY-BKCFRK2K.js} +206 -56
  34. package/dist/ms_MY-BKCFRK2K.js.map +1 -0
  35. package/dist/{pl-ADNVRP55.js → pl-3IKQRG3Y.js} +206 -56
  36. package/dist/pl-3IKQRG3Y.js.map +1 -0
  37. package/dist/{pt-OL2DR3DO.js → pt-PZHV5EZE.js} +206 -56
  38. package/dist/pt-PZHV5EZE.js.map +1 -0
  39. package/dist/quickcharts.css +2060 -717
  40. package/dist/{resources-C0cYryO9.d.ts → resources-Le6flcEn.d.ts} +1 -1
  41. package/dist/{ru-V6YFEPAF.js → ru-BAL6RQUV.js} +206 -56
  42. package/dist/ru-BAL6RQUV.js.map +1 -0
  43. package/dist/{sv-TORXQVE7.js → sv-Y6GBGDHM.js} +206 -56
  44. package/dist/sv-Y6GBGDHM.js.map +1 -0
  45. package/dist/{symbols-BL1fD4CS.d.ts → symbols-6V22WaRX.d.ts} +1 -1
  46. package/dist/symbols.d.ts +1 -1
  47. package/dist/{th-K6SJSYSY.js → th-MAMLMZKU.js} +206 -56
  48. package/dist/th-MAMLMZKU.js.map +1 -0
  49. package/dist/theme-manifest.json +204 -16
  50. package/dist/{tr-4AEM66KW.js → tr-3LQHINUZ.js} +206 -56
  51. package/dist/tr-3LQHINUZ.js.map +1 -0
  52. package/dist/{vi-YU5XCEUU.js → vi-GR4PSDKP.js} +206 -56
  53. package/dist/vi-GR4PSDKP.js.map +1 -0
  54. package/dist/{zh-QXKRYHU5.js → zh-2RJ5VNAI.js} +206 -56
  55. package/dist/zh-2RJ5VNAI.js.map +1 -0
  56. package/dist/{zh_TW-AYPDKG4Q.js → zh_TW-XEBSACHU.js} +206 -56
  57. package/dist/zh_TW-XEBSACHU.js.map +1 -0
  58. package/package.json +1 -1
  59. package/dist/ar-KSXQ2USS.js.map +0 -1
  60. package/dist/ca_ES-JG4FM55E.js.map +0 -1
  61. package/dist/chunk-YR7NT5ZW.js +0 -6997
  62. package/dist/chunk-YR7NT5ZW.js.map +0 -1
  63. package/dist/de-VSW2LHNF.js.map +0 -1
  64. package/dist/es-5ZXIPVOB.js.map +0 -1
  65. package/dist/fr-4F6DAWGD.js.map +0 -1
  66. package/dist/he_IL-B7PBQUEV.js.map +0 -1
  67. package/dist/id_ID-CYJRMXPC.js.map +0 -1
  68. package/dist/it-KTX4SG5P.js.map +0 -1
  69. package/dist/ja-V7OURU5D.js.map +0 -1
  70. package/dist/ko-2RNEBYVE.js.map +0 -1
  71. package/dist/ms_MY-EY235E7Q.js.map +0 -1
  72. package/dist/pl-ADNVRP55.js.map +0 -1
  73. package/dist/pt-OL2DR3DO.js.map +0 -1
  74. package/dist/ru-V6YFEPAF.js.map +0 -1
  75. package/dist/sv-TORXQVE7.js.map +0 -1
  76. package/dist/th-K6SJSYSY.js.map +0 -1
  77. package/dist/tr-4AEM66KW.js.map +0 -1
  78. package/dist/vi-YU5XCEUU.js.map +0 -1
  79. package/dist/zh-QXKRYHU5.js.map +0 -1
  80. package/dist/zh_TW-AYPDKG4Q.js.map +0 -1
package/README.md CHANGED
@@ -1627,7 +1627,13 @@ chrome is painted from it and renders nothing without it.
1627
1627
  asks where to begin rather than choosing a starting bar. Its starting-point menu answers with a
1628
1628
  bar picked on the plot, a date, the first available date, or a random bar. The first available
1629
1629
  date runs `chart.replay.startFirst`: the chart pages the feed's history back to its oldest bar,
1630
- within the 20,000 bars one session holds, and starts there. Undo and
1630
+ within the 20,000 bars one session holds, and starts there. A date opens Select date over the
1631
+ undimmed chart, carried by its title: a date field, on an intraday chart a time field whose clock
1632
+ lists the day in quarter hours, a calendar of the loaded window whose heading turns to the months
1633
+ and the years, and a chip that moves the choice to the first available day. Picking moves the
1634
+ choice and the dialog stays up; Select starts replay at the first bar at or after the date and
1635
+ time, in UTC, and Cancel leaves replay asking where to start. The arrows walk the days, Page Up
1636
+ and Page Down turn the month, Enter picks and Escape closes. Undo and
1631
1637
  redo step back and forward through the active chart's own content, and each names the change it
1632
1638
  would move. Layout setup offers the arrangements and sync switches the chart offers (by default
1633
1639
  the 55 arrangements and the five sync switches); the saved-layouts menu, shown with a layouts
@@ -1743,9 +1749,9 @@ reports through the `image` event (a refused copy falls back to a download). Eac
1743
1749
  in `ui`; hiding one removes the control and leaves its commands.
1744
1750
 
1745
1751
  ```ts
1746
- import { createChart, createUdfDatafeed } from '@trdrs/quickcharts'
1752
+ import { createChart, createUdfDatafeed, type ChartDatafeed } from '@trdrs/quickcharts'
1747
1753
 
1748
- declare const portfolio: { name: string } | null
1754
+ declare const portfolio: { name: string; search: ChartDatafeed['search'] } | null
1749
1755
 
1750
1756
  const trimmed = createChart({
1751
1757
  container,
@@ -1753,7 +1759,7 @@ const trimmed = createChart({
1753
1759
  ui: { navigation: false, topBar: { layouts: false, image: false } },
1754
1760
  search: {
1755
1761
  classNames: { future: 'Futures', crypto: 'Crypto' },
1756
- scope: () => (portfolio ? { label: portfolio.name } : null),
1762
+ scope: () => (portfolio ? { label: portfolio.name, search: portfolio.search } : null),
1757
1763
  },
1758
1764
  preferences: { savedTimeframes: ['1m', '15m', '1h', '1d'], layoutAutosave: true },
1759
1765
  })
@@ -1763,9 +1769,9 @@ trimmed.on('saveNeeded', () => note('the layout has unsaved changes'))
1763
1769
  The search dialog's class chips come from your datafeed's `config().classes`, named through
1764
1770
  `search.classNames`; a class you do not name wears its token. `search.spreads`,
1765
1771
  `search.allClasses` and `search.classSelection` choose how the classes and the spread operators are
1766
- offered, as "Classes and spread operators" under Search describes. `search.scope` names what your
1767
- search is limited to at the far edge of that strip, with the mark its `mark` paints; your datafeed
1768
- decides what is found. The range presets read your
1772
+ offered, as "Classes and spread operators" under Search describes. `search.scope` offers a part of
1773
+ the catalog the viewer can limit the search to, as a chip at the far edge of that strip, as "A
1774
+ search scope" under Search describes. The range presets read your
1769
1775
  datafeed's optional `earliestBar(symbol)`: a preset deeper than the history you serve is disabled.
1770
1776
 
1771
1777
  ```ts
@@ -2019,6 +2025,60 @@ inventory, and the built-in palettes and the generated stylesheet are built from
2019
2025
  property names are private, so a color, a size or a radius is always set through a role. The
2020
2026
  class names inside the stylesheet are private too, except the supported hooks below.
2021
2027
 
2028
+ ### The built-in palettes
2029
+
2030
+ The two built-in palettes paint every dialog, menu and popover the chart opens from these roles,
2031
+ among the others `THEME_ROLES` lists:
2032
+
2033
+ | Role | Light | Dark | What it paints |
2034
+ |---|---|---|---|
2035
+ | `overlay.surface` | `#ffffff` | `#1f1f1f` | The ground of a dialog, menu or popover. |
2036
+ | `overlay.separator` | `#ebebeb` | `#4a4a4a` | The rule under a dialog header and over its footer, and between menu groups. |
2037
+ | `overlay.scrim` | `rgba(156, 156, 156, 0.5)` | `rgba(0, 0, 0, 0.5)` | The veil behind a modal dialog. |
2038
+ | `text.primary` | `#0f0f0f` | `#dbdbdb` | The ink of rows, labels and values. |
2039
+ | `text.muted` | `#6a6a6a` | `#9b9b9b` | A section title, a hint, a placeholder. |
2040
+ | `chrome.caret` | `#707070` | `#8c8c8c` | The chevron of a select and the arrow that opens a flyout. |
2041
+ | `text.link` | `#2962ff` | `#5b9cf6` | A text link. |
2042
+ | `state.hover` | `#f2f2f2` | `#2e2e2e` | The fill under the pointer. |
2043
+ | `state.pressed` | `#ebebeb` | `#3d3d3d` | The fill while the pointer is down. |
2044
+ | `control.outline` | `#2e2e2e` | `#ffffff` | The edge and the words of an outlined button at rest, such as a dialog's Cancel. |
2045
+ | `control.onInk` | `#ffffff` | `#000000` | A mark cut from the emphasis fill: a chosen thickness, line style or line end. |
2046
+ | `control.neutral` | `#f2f2f2` | `#2e2e2e` | The quiet fill: a dialog's shortcut chip, the band over a calendar's columns, a chosen month or year. |
2047
+ | `control.neutralHover` | `#ebebeb` | `#3d3d3d` | The quiet fill under the pointer. |
2048
+ | `control.neutralPressed` | `#dbdbdb` | `#4a4a4a` | The quiet fill while the pointer is down. |
2049
+ | `control.neutralInk` | `#000000` | `#ffffff` | The words on the quiet fill, and what a quiet control's words and mark brighten to under the pointer, such as a calendar's day. |
2050
+ | `status.positive` | `#078671` | `#089981` | A gain or a success. |
2051
+ | `status.negative` | `#df323f` | `#f34452` | A loss or a failure. |
2052
+ | `status.warning` | `#ac6600` | `#ff9800` | A condition to notice before acting. |
2053
+
2054
+ Every ink is held to the WCAG 2.2 AA ratio on each ground it is drawn over, so the light status
2055
+ inks are the darkest steps of their hues that still read at 4.5 to 1 on white, the dark red reads at
2056
+ 4.5 to 1 on the dialog ground, and the muted ink reads at 4.5 to 1 over the hover and selected fills
2057
+ of a menu row and over the quiet fill. `drawing.line` is `#2962ff` in both modes; `drawing.selected`,
2058
+ the ring of a selected drawing's handles, is `#2962ff` light and `#1e53e5` dark, around a center of
2059
+ `drawing.handle`, the chart's own ground.
2060
+
2061
+ ### Fields
2062
+
2063
+ Every text field, select, number field and color well the chart draws in its dialogs and settings
2064
+ is one box: 34px tall, a 1px edge with an 8px corner around a clear ground, and its words at 14 on
2065
+ 18, 8px in from the edge. A select ends in an 18px chevron in `chrome.caret`. Five roles in the
2066
+ `control` family paint the box, and the focus ring is `state.focusRing`:
2067
+
2068
+ | Role | Light | Dark | What it paints |
2069
+ |---|---|---|---|
2070
+ | `control.fieldEdge` | `#dbdbdb` | `#575757` | The edge of a field at rest. |
2071
+ | `control.fieldEdgeHover` | `#a8a8a8` | `#707070` | The edge of a field under the pointer. |
2072
+ | `control.selectEdgeHover` | `#a8a8a8` | `#808080` | The edge of a list button under the pointer, such as a select on a drawing's settings page. |
2073
+ | `control.fieldInvalid` | `#f23645` | `#f23645` | The edge and the focus ring of a field holding a value it refuses. |
2074
+ | `control.fieldFill` | `#f2f2f2` | `#2e2e2e` | The ground of a field that is read-only or disabled. |
2075
+
2076
+ Focus draws a 2px ring over the edge, the edge itself and the pixel inside it, so the ring follows
2077
+ the corner and a dialog that scrolls never clips it. Only a value the chart refuses turns the edge
2078
+ `control.fieldInvalid`; a number past its bounds or off its step is clamped or rounded, so its
2079
+ field never turns red. The symbol search field draws its own outline in
2080
+ `chrome.fieldBorder`.
2081
+
2022
2082
  ### Motion
2023
2083
 
2024
2084
  Every duration, timing function and motion scale the chart uses is a role in the `motion` family,
@@ -2032,21 +2092,25 @@ same values:
2032
2092
  | `motion.durationModerate` | `250ms` | A control moving to its new state, such as a switch knob sliding. |
2033
2093
  | `motion.durationSlow` | `350ms` | A small mark settling, such as a disclosure caret turning or a checkbox filling. |
2034
2094
  | `motion.durationSlower` | `500ms` | A larger mark turning, such as the drawing toolbar's chevron. |
2095
+ | `motion.durationGlide` | `100ms` | A mark gliding to a new place, such as a dialog's tab bar or an opacity knob. |
2035
2096
  | `motion.easingStandard` | `ease` | A modal dialog box, the replay row, a caret dip, a checkbox fill. |
2036
2097
  | `motion.easingOut` | `ease-out` | A modal backdrop fading, a switch knob sliding. |
2037
2098
  | `motion.easingLinear` | `linear` | A color or opacity change under the pointer. |
2038
2099
  | `motion.easingSpring` | `cubic-bezier(0.175, 0.885, 0.32, 1.275)` | A caret or chevron turning with a slight overshoot. |
2100
+ | `motion.easingInOut` | `ease-in-out` | A dialog's tab bar sliding to the page shown. |
2039
2101
  | `motion.scaleEnter` | `0.97` | The scale a modal dialog box grows from as it opens. |
2040
2102
 
2041
2103
  Every modal dialog the chart opens (the symbol search, chart settings, the indicator browser and
2042
- indicator settings, the saved-layouts browser, the name and confirm prompts, go to date, and the
2043
- drawing settings, image picker and template prompts) opens with its backdrop fading in over
2104
+ indicator settings, the saved-layouts browser, the name and confirm prompts, and the drawing image
2105
+ picker and template prompts) opens with its backdrop fading in over
2044
2106
  `motion.durationBase` on `motion.easingOut`, and its box fading in and growing from
2045
2107
  `motion.scaleEnter` to full size over `motion.durationBase` on `motion.easingStandard`. It closes
2046
2108
  with the same motion reversed. A closing dialog stops taking input and returns focus at once, and the
2047
2109
  chart removes it when the same `motion.durationBase` has elapsed, so a duration you set times both
2048
2110
  the transition and the removal. A dialog opened over another moves on its own and closes first, and
2049
- a dialog the chart replaces or tears down goes at once.
2111
+ a dialog the chart replaces or tears down goes at once. The drawing settings dialog and the replay
2112
+ date picker work on the chart they stand over, so they open in place: they appear and leave at once,
2113
+ and their backdrop dims nothing while still taking the press that closes them.
2050
2114
 
2051
2115
  A duration takes a CSS duration such as `200ms` or `0.2s`; an easing takes any CSS timing function,
2052
2116
  such as `ease-in-out`, `steps(4)` or `cubic-bezier(0.2, 0, 0, 1)`; a scale takes a unitless factor
@@ -2074,7 +2138,8 @@ The stylesheet declares two cascade layers and puts everything it contains in th
2074
2138
  palettes in `quickcharts.tokens`, every recipe in `quickcharts.chart`. Nothing in it is unlayered.
2075
2139
  It marks a declaration `!important` only where a later layer or an inline palette must not undo it:
2076
2140
  an element's `hidden` attribute, the zero motion durations under a reduced-motion preference, and
2077
- the missing focus ring of a search field, which shows its focus by its caret. Your first stylesheet
2141
+ the focus outline a field leaves off, because a field shows its focus on its own box: the ring over
2142
+ its edge, or the caret in a search field. Your first stylesheet
2078
2143
  must declare the complete order before any product stylesheet loads, because a layer's position is
2079
2144
  fixed by the first statement that names it:
2080
2145
 
@@ -2453,6 +2518,75 @@ void multi
2453
2518
 
2454
2519
  `openSymbolSearch` and `mountSymbolSearch` take the same three options beside their `classes`.
2455
2520
 
2521
+ ### A search scope
2522
+
2523
+ `search.scope` offers a part of the catalog the viewer can limit the search to: a portfolio, a
2524
+ watchlist, or any other set of symbols you can search within. The symbol search shows it as a chip
2525
+ at the far edge of the class strip, wearing the scope's mark and label, and the chip is on each time
2526
+ the dialog opens unless the scope says `on: false`. `scope` is read each time the dialog opens, so
2527
+ it follows what your page has selected; null offers no chip.
2528
+
2529
+ While the chip is on, the dialog searches with the scope's `search`, which the chart's search
2530
+ controller asks exactly as it asks your datafeed's: the query after the debounce, the selected
2531
+ classes as `cls` or `classes`, a page at a time through `limit` and `offset`, and a newer question
2532
+ retiring an older one's answer. Answer with a page, as your datafeed does. A dialog that opens with
2533
+ the chip on asks the scope at once, and the scope's completed pages are reused while the dialog is
2534
+ open and go when it closes: the widget's catalog cache holds your datafeed's pages alone. The list
2535
+ leads with the scope's `recents`, or with none when the scope keeps none. While the chip is off,
2536
+ the dialog searches your datafeed and leads with the chart's recents.
2537
+
2538
+ Pressing the chip asks the other source the query and classes the dialog holds, and an answer that
2539
+ arrives for the state the viewer left is dropped. A pick is recorded in `search.recents` either way,
2540
+ and in the scope's `recents` too while the chip is on. The compare dialog, adding a comparison or
2541
+ changing one, offers no scope and searches your datafeed.
2542
+
2543
+ | Field | What it is |
2544
+ |---|---|
2545
+ | `label` | The scope's name, written on the chip. |
2546
+ | `mark` | Paints the scope's mark into the chart's 18px box at the chip's leading edge, and returns what takes it down. Absent, the chip wears the label's initial. |
2547
+ | `search` | Searches within the scope, called as your datafeed's `search` is. Required. |
2548
+ | `recents` | The recent picks the list leads with while the chip is on, and where a pick made then is recorded too. Absent, the list leads with none. |
2549
+ | `on` | Whether the chip is on when the dialog opens. Default `true`. |
2550
+
2551
+ The chip is a toggle button in the strip's tab order, after the class chips. `aria-pressed` says
2552
+ whether the search is limited, and its accessible name says what a press does: "Limit search to"
2553
+ and the scope's label, in the viewer's language.
2554
+
2555
+ ```ts
2556
+ import { createChart, createUdfDatafeed, memoryRecents, type SearchScope } from '@trdrs/quickcharts'
2557
+
2558
+ declare const watchlist: { id: string; name: string; logo: string } | null
2559
+
2560
+ const watchlistRecents = memoryRecents()
2561
+
2562
+ const scoped = createChart({
2563
+ container,
2564
+ datafeed: createUdfDatafeed({ baseUrl: 'https://feed.example.com/udf' }),
2565
+ search: {
2566
+ scope: (): SearchScope | null => {
2567
+ if (!watchlist) return null
2568
+ const { id, name, logo } = watchlist
2569
+ return {
2570
+ label: name,
2571
+ mark: ({ host, size }) => {
2572
+ const image = document.createElement('img')
2573
+ image.src = logo
2574
+ image.alt = ''
2575
+ image.width = size
2576
+ image.height = size
2577
+ host.append(image)
2578
+ return () => image.remove()
2579
+ },
2580
+ // Asked as your datafeed is: the query, `cls` or `classes`, `limit` and `offset`.
2581
+ search: (query, options) => myBackend.searchWatchlist(id, query, options),
2582
+ recents: watchlistRecents,
2583
+ }
2584
+ },
2585
+ },
2586
+ })
2587
+ void scoped
2588
+ ```
2589
+
2456
2590
  ### The picker, away from a chart
2457
2591
 
2458
2592
  A page that picks a market where no chart is mounted opens the same dialog the chart's symbol pill
@@ -2682,7 +2816,7 @@ re-tile opens in the current one.
2682
2816
 
2683
2817
  ## Drawings
2684
2818
 
2685
- The widget ships with a complete drawing product, on by default: every one of the 90 tools places
2819
+ The widget ships with a complete drawing product, on by default: every one of the 89 tools places
2686
2820
  from the toolbar, the selected drawing gets a floating settings bar and a settings dialog, tool
2687
2821
  defaults and named templates ride the adapter's template family, and a symbol's drawings persist
2688
2822
  through the adapter's drawings family. Turn the whole layer off with `features.drawings: false`,
@@ -2757,11 +2891,164 @@ line style, the settings gear, lock, delete, and a More menu with the stacking m
2757
2891
  per-timeframe visibility presets, clone, copy and hide. Every edit persists at once and becomes the
2758
2892
  tool's default for the next drawing of that type. The settings dialog opens from the gear with
2759
2893
  Inputs, Style, Text, Table, Coordinates and Visibility pages as the tool has them; its edits apply
2760
- live, Cancel restores the drawing, and Ok commits the session as one edit.
2761
-
2762
- Text-bearing tools open an inline editor where the text sits, in the drawing's own type. A fresh
2763
- placement committed empty is removed; an existing note committed empty is blanked. Ctrl or Cmd
2764
- with Enter commits, Escape cancels, and a press on the chart commits.
2894
+ live, Cancel restores the drawing, and Ok commits the session as one edit. Its header carries the
2895
+ drawing's name, the tool's own until the viewer renames it with the pencil beside it; the name is
2896
+ `DrawingOptions.name`, saved with the drawing, and Cancel restores it with the rest. A page shown
2897
+ puts the keyboard in its first field, and the dialog keeps its top edge where it opened as pages of
2898
+ other sizes come and go. Its lists hang under the controls that open them, past the dialog's edge
2899
+ where they need to. The Template menu saves the current setup under a name, applies a saved one,
2900
+ or applies the tool's defaults: its own look and setup, put on the drawing at once, with its words
2901
+ kept.
2902
+
2903
+ A color in the dialog opens its popover under the button that holds it: the offered colors, the
2904
+ colors the viewer added with the plus after them, and the opacity, and for a stroke its thickness
2905
+ and line style. Every choice applies at once and the popover stays up for the next one; Escape
2906
+ returns to the button. The plus opens a custom color editor that takes a hex of three or six digits
2907
+ or a pick on its saturation and brightness area and hue strip. A color added there joins the
2908
+ viewer's own, newest first, kept with the drawing preferences in `ChartStorage`, and the settings
2909
+ bar's palette offers them too.
2910
+
2911
+ The line tools' Style page carries the stroke with its two ends, the extensions, the middle point,
2912
+ the price labels and, under Info, the stats a line reads (price range, percent change, the change
2913
+ counted in the symbol's smallest price move, bars, date and time range, angle), where they stand
2914
+ (left, center, right, or auto, which keeps them inside the pane), and whether they show always or
2915
+ only while the line is selected. A horizontal line offers its price label, a vertical line its time
2916
+ label, a cross line both. A rectangle offers its extensions, its border, a middle line with a stroke
2917
+ of its own and its background; every other shape its border and background; a curve its stroke and
2918
+ ends, its extensions along the tangents it ends on, and its background. A background switched off
2919
+ keeps its color and opacity for when it is switched back on. The Text page sets the words' color,
2920
+ size, weight and slant on one line over the words, and where the tool places them, where they stand:
2921
+ above, on or below a line, above, inside or below a box, along it from left to right, and for a
2922
+ vertical line whether they read across it or run up it. `NO_COORDINATES_TAB` names the tools whose
2923
+ points are drawn rather than typed, and `PRICE_ONLY_COORDS` the levels that span every bar.
2924
+
2925
+ A retracement, a trend-based extension and a fib channel lay their levels out two to a line, each
2926
+ level its switch, its value and its color, under the thickness and style every level line is drawn
2927
+ in. The one color recolors every level at once, and shows the color the levels share or a split
2928
+ well while they differ. The bands between levels fill at `backgroundOpacity` while
2929
+ `fillBackground` holds them; `coeffsAsPercents` reads a level's ratio as a percent, and
2930
+ `labelsHAlign` and `labelsVAlign` stand the labels before, at the middle of or after the levels,
2931
+ above, on or below each line. A retracement and an extension draw their trend line through the
2932
+ swing points in a stroke of its own (`trendLine`, `trendLineColor`, `trendLineWidth`,
2933
+ `trendLineStyle`), stand each level's own words where `showText`, `textHAlign` and
2934
+ `textVAlign` put them, and with `levelsOnLogScale` divide the swing by log price while the price
2935
+ scale is logarithmic, which `Viewport.logScale` reports.
2936
+
2937
+ A time zone, a trend-based time, fib circles, speed resistance arcs, a fib wedge and a pitchfan
2938
+ stand their levels one to a line, each level its switch, its value and its own stroke: a level's
2939
+ `width` and `style` draw it apart from the drawing's own. A time zone and a trend-based time label
2940
+ their lines where `labelsHAlign` and `labelsVAlign` put them along and across the pane; a circle
2941
+ fib reads its ratios as percents with `coeffsAsPercents`; an arc fib closes its arcs into circles
2942
+ with `fullCircles`; the trend-based time, the circles, the arcs and the wedge draw a trend line in a
2943
+ stroke of its own, and a pitchfan its median (`medianColor`, `medianWidth`, `medianStyle`). A
2944
+ speed resistance fan and a gann box divide their box on `priceLevels` across it and `timeLevels`
2945
+ down it, each side's labels switched on their own; a fan draws a grid at the divisions in a stroke
2946
+ of its own, and a gann box shades its price and time bands on their own switches and draws its
2947
+ angles corner to corner in `anglesColor`. `reverse` counts a box's divisions from the other
2948
+ corner.
2949
+
2950
+ A pitchfork stands its line pairs one to a line the same way, each pair its switch, its value and
2951
+ its own stroke, under its median's stroke (`medianColor`, `medianWidth`, `medianStyle`) and over
2952
+ the bands between pairs, each in its outer pair's color at `backgroundOpacity` while
2953
+ `fillBackground` is on. `extendLines` runs every line back past the fork's start, and `variant`
2954
+ switches its construction in place: `original`, `schiff`, `modified_schiff` or `inside`.
2955
+ A fib spiral winds clockwise out from its first point, and `counterclockwise` winds it the other
2956
+ way.
2957
+
2958
+ A gann square and a gann square fixed draw a grid of six lines at their fifths (`levels`), fan
2959
+ lines from the corner they count from out to their far sides (`fans`) and arcs about that corner
2960
+ (`arcs`), each line its switch, its color and its width, a fan line or an arc at its ratio of the
2961
+ square's unit, `x` along the time side for `y` along the price side. Their pages set each set
2962
+ under its section, two to a line; the bands between arcs follow `fillBackground` and
2963
+ `backgroundOpacity`, and `reverse` counts from the other corner. A gann square holds its second
2964
+ corner at `scaleRatio` price for every bar between its corners, a ratio it takes from the pane
2965
+ when it is first drawn so it opens square, and typing a Price/bar ratio moves the corner to it; with
2966
+ `showLabels` it reads its price and bar ranges and their ratio under it. A square fixed stays
2967
+ square on the pane whatever its scale. A gann fan draws its rays at their price-to-time ratios, 1/8
2968
+ to 8/1, each in its own stroke, with the bands between them and each ray's ratio at its end.
2969
+
2970
+ A regression trend fits its line through the `source` of the bars between its points: a bar's
2971
+ open, high, low, close or volume, or one of the averages `hl2`, `hlc3`, `ohlc4` and `hlcc4`
2972
+ (`BAR_PRICE_SOURCES`). Its bands stand `upperDeviation` and `lowerDeviation` standard deviations
2973
+ from it, the lower counted down, each shown by `useUpper` and `useLower`; the line and each band
2974
+ switch and stroke on their own (`baseLine`, `upLine`, `downLine` with their colors, widths and
2975
+ styles), `extendLines` runs them to the pane's edges, and `showPearsons` reads the correlation
2976
+ under them.
2977
+
2978
+ A parallel channel draws its levels at ratios of its width, 0 its baseline and 1 the parallel through
2979
+ its third point, each level its switch, its value and its own stroke, over its body between 0 and 1.
2980
+ A flat top/bottom and a disjoint channel end their sides as `leftEnd` and `rightEnd` set and read
2981
+ each side's prices at its ends with `showPrices`, in `pricesColor`, `pricesFontSize`,
2982
+ `pricesBold` and `pricesItalic`. A channel's `fillBackground` switches its body, and its words
2983
+ stand above it, inside it or below it with `textVAlign`, at its start, middle or end with
2984
+ `textHAlign`. A parallel channel's Coordinates page writes its third point as the price its
2985
+ parallel stands from the baseline.
2986
+
2987
+ A sector shades the two halves of its slice, parted by the ray through its arc's middle, in `color1`
2988
+ and `color2` while `fillBackground` is on. A bars pattern paints its captured bars as `mode` says:
2989
+ `hl` their high-low ranges, `oc` their open-close ranges, or a line through each bar's close, open,
2990
+ high, low or `hl2`. A ghost feed's average candle span is held as a price and written on its page in
2991
+ the symbol's minimum ticks.
2992
+
2993
+ An anchored VWAP weighs the `source` of every bar since its point by the bar's volume, and stands
2994
+ its bands off the average by `bandMultipliers` standard deviations or, with `bandsMode`
2995
+ `percent`, percents of it, each band calculated while its `bandsOn` switch is on. A volume profile
2996
+ reads its rows' volumes beside them with `showValues` and its point of control and shown value
2997
+ area bounds on the price scale with `showLabelsOnPriceScale`. A range meter reads the stats its
2998
+ switches choose in a label of its own color, size and background.
2999
+
3000
+ A text's box switches its background (`fillBackground`) and its border (`drawBorder`, in the
3001
+ drawing's stroke color) on their own, and with `wordWrap` its words wrap at `wordWrapWidth` pixels;
3002
+ a callout's words wrap the same way inside a border at the drawing's width. A note ties a label to
3003
+ the point it notes: its first point is that point, its second the label's, with a line between them
3004
+ in the drawing's stroke color and the label's border in `borderColor`; a pin's words stand in a box
3005
+ of the same kind under its marker. A price note runs a line from its price to a tag that reads it,
3006
+ the tag in a text style and colors of its own (`labelTextColor`, `labelFontSize`, `labelBold`,
3007
+ `labelItalic`, `labelBackgroundColor`, `labelBorderColor`), its words along the line where
3008
+ `textVAlign` and `textHAlign` stand them. A signpost stands on its bar's high, or its low for a
3009
+ plate below the bar, its plate `position` percent of the pane's height away, so the plate keeps its
3010
+ height over the bar as the price scale moves; with `showImage` the plate leads with its `emoji`,
3011
+ and its words read in white or black, whichever reads on the plate. A table stands its cells' words
3012
+ at their left, middle or right with `textHAlign`, its border and grid in the drawing's stroke color.
3013
+
3014
+ A brush fills the area its stroke closes back to its start while `fillBackground` is on, and a brush
3015
+ and a path head their ends with arrows as `leftEnd` and `rightEnd` say, a path with an arrow at its
3016
+ last point at first. A highlighter's width is in pixels, 8 to 96 on its page. The emoji and the
3017
+ sticker have no settings beyond their visibility: a glyph's size is set by its grips on the chart. An
3018
+ icon's page sets its tint, and an image's page chooses its picture from a
3019
+ box that names the formats and the size the intake takes, and sets how see-through it is drawn.
3020
+
3021
+ The pattern tools are read by their letters and carry no words of their own: their Style page sets
3022
+ the letters' color, size, weight and slant on a Label row, then the border and, for the patterns
3023
+ that shade their legs, the background, which `fillBackground` switches off and on keeping its
3024
+ color. A three drives pattern stands on seven points, its reversal after the third drive the last.
3025
+
3026
+ An Elliott wave count writes its labels in its wave's color, as its `degree` writes them: the
3027
+ fifteen degrees from `supermillennium` to `minuscule` (`ELLIOTT_DEGREES`) stand in five threes,
3028
+ each three ringed, in parentheses and bare, in roman numerals or figures and in capitals or small
3029
+ letters. `showWave` switches the wave through its pivots, and the labels stand without it.
3030
+
3031
+ The text, the comment, the note, the signpost, the callout and the pin type their words on the
3032
+ chart. The drawing paints the words as they are typed, with their caret, selection and
3033
+ placeholder, while a field nobody sees, laid exactly over them in their own type and line height,
3034
+ takes the keys: the session's `inline` (`TextInlineEdit`) says where the words stand
3035
+ (`TextEditFrame`) and hears what the field holds (`TextDraft`). Enter and Shift with Enter break
3036
+ the line; Escape, Ctrl or Cmd with Enter, and a press elsewhere commit the words exactly as typed,
3037
+ the drawing still selected after Escape. A click on the words of the selected drawing types again,
3038
+ and a double-click opens its settings. A text, a comment, a note or a signpost left without words
3039
+ stays while it is selected and goes once it is not; a callout left without words goes as its edit
3040
+ ends; a pin keeps its place without words. `AttachDrawingsOptions.placeholder` names the words an
3041
+ empty drawing shows and `AttachDrawingsOptions.inks` the chart's own inks (`DrawingInks`).
3042
+
3043
+ A table types into the cell a click on the selected table lands in, Tab moving on to the next cell
3044
+ and from the last to the first. Its floating bar and the chart's menu over it add a column right of
3045
+ the cell last typed in and a row below it, or at the table's ends where no cell is, and the menu
3046
+ removes that cell's row and column (`chart.drawings.tableRemoveRow`,
3047
+ `chart.drawings.tableRemoveColumn`). A hovered grid line resizes its column or row, and the corners
3048
+ scale the table. The price label, the price note, the arrow marks, the arrow marker and the flag
3049
+ open no editor: their words, where they have any, are set in their settings, which a double-click
3050
+ opens. Any other text-bearing tool types in a box of its own: Ctrl or Cmd with Enter commits,
3051
+ Escape cancels, and a press on the chart commits.
2765
3052
 
2766
3053
  Templates are named setups a viewer saves from either surface and applies on demand. They and
2767
3054
  the remembered defaults ride `ChartSaveLoadAdapter.templates('drawing')`, so a host that keeps
@@ -2776,7 +3063,9 @@ adapter they last the page.
2776
3063
 
2777
3064
  The image and glyph tools reach your host through `ChartWidgetOptions.assets`. `intakeImage`
2778
3065
  turns a picked file into a payload within the caps and answers a refusal as a code the chart
2779
- resolves through its own catalog; `glyphSource` answers the artwork URL an emoji or sticker draws
3066
+ resolves through its own catalog. The payload's `dataUrl` is always a PNG or a JPEG, whatever the
3067
+ picked file was, so a saved chart opens everywhere: decode a WEBP and re-encode it on a canvas, as a
3068
+ PNG where it has transparency and a JPEG otherwise; `glyphSource` answers the artwork URL an emoji or sticker draws
2780
3069
  with, or null to draw the glyph as text. Emoji artwork from Twemoji is bundled and works without
2781
3070
  an asset port or external requests. Omit `glyphSource` to use it. It is a chunk of its own, which
2782
3071
  the chart imports the first time it draws an emoji, so a chart that never shows one never loads
@@ -2793,6 +3082,8 @@ layer.armTool('rectangle')
2793
3082
  layer.destroy()
2794
3083
  ```
2795
3084
 
3085
+ A layer you mount yourself is told the symbol's grid, formatter and currency through `setTick`,
3086
+ `setPriceFormatter` and `setCurrency`; a position offers its risk as an amount in that currency.
2796
3087
  A layer you mount yourself arms whatever you arm. Its `copies` option answers whether a new drawing
2797
3088
  may be made as a copy of a drawing of a type: return false for a tool you do not offer, and clone,
2798
3089
  paste and a Control- or Command-drag duplicate make nothing for its drawings, `canPaste` answers
@@ -2806,7 +3097,7 @@ never imports any of it.
2806
3097
  ```ts
2807
3098
  import { buildDrawingToolbarGroups, drawingTools, parseDrawingsStore, restoreDrawings, serializeDrawingsStore } from '@trdrs/quickcharts/drawings'
2808
3099
 
2809
- // The catalog: 90 tools in 14 categories, read-only.
3100
+ // The catalog: 89 tools in 14 categories, read-only.
2810
3101
  const trendLine = drawingTools.get('trend_line')
2811
3102
  const fibs = drawingTools.byCategory('fibonacci')
2812
3103
 
@@ -2846,8 +3137,9 @@ const preset = await templates.defaultFor('trend_line')
2846
3137
  ```
2847
3138
 
2848
3139
  Image-backed and glyph tools reach the host through one explicit asset port. The library owns the
2849
- rules (JPG or PNG, 2 MB, a 2000 px longest edge, downscaled rather than refused) and names each
2850
- refusal with a code that resolves through the chart's own catalog; the host owns the bytes.
3140
+ rules (a JPG, a PNG or a WEBP, stored as a PNG or a JPEG, 2 MB, a 2000 px longest edge, downscaled
3141
+ rather than refused) and names each refusal with a code that resolves through the chart's own
3142
+ catalog; the host owns the bytes.
2851
3143
 
2852
3144
  ```ts
2853
3145
  import { checkImageFile, fittedSize, IMAGE_ACCEPT, type DrawingAssetPort } from '@trdrs/quickcharts/drawings'
@@ -2857,7 +3149,8 @@ const assets: DrawingAssetPort = {
2857
3149
  const bad = checkImageFile(file)
2858
3150
  if (bad) return { ok: false, ...bad }
2859
3151
  const { width, height } = fittedSize(1200, 900)
2860
- return { ok: true, asset: { dataUrl: await myBackend.read(file), width, height, downscaled: false } }
3152
+ // A PNG or a JPEG whatever the picked file was: a WEBP is re-encoded before it is stored.
3153
+ return { ok: true, asset: { dataUrl: await myBackend.pngOrJpeg(file), width, height, downscaled: false } }
2861
3154
  },
2862
3155
  // Optional: glyphSource replaces the bundled emoji artwork.
2863
3156
  // glyphSource: (glyph) => myBackend.emojiUrl(glyph),
@@ -2873,14 +3166,21 @@ What to know:
2873
3166
  - **Every tool places.** Fixed-anchor tools place by press-drag-release or click then click; an
2874
3167
  instant tool (the position tools) lands whole from one press; a multipoint tool adds a point per
2875
3168
  click until a double-click ends the run; a freehand tool captures the drag as a stroke; a
2876
- text-bearing tool opens the inline editor as it lands. `armTool` **throws** only for a name the
2877
- catalog does not know, and `placeableByWidget(type)` answers in advance.
3169
+ text-bearing tool opens the inline editor as it lands; a right-click while a drawing is half
3170
+ placed takes it back and puts the tool down. `armTool` **throws** only for a name the catalog does
3171
+ not know, and `placeableByWidget(type)` answers in advance.
2878
3172
  - **Persistence speaks a shared codec.** The store document (`{ [symbol]: SerializedDrawing[] }`,
2879
3173
  via `parseDrawingsStore`/`serializeDrawingsStore`) is the SAME document every host of the codec
2880
3174
  reads and writes, so drawings survive moving between hosts. A drawing bound to one chart (sync
2881
3175
  off) lives in the adapter's chart-bound scope for the symbol; a shared drawing lives in the
2882
3176
  symbol's scope, and a refused write merges the stored document over the layer's own before it
2883
3177
  writes again.
3178
+ - **A save keeps its look.** A drawing saves at `v: 3`. A save at `v: 2` restores with the look it
3179
+ was saved with: its tool writes the values that paint it so and saves at `v: 3` with them, the
3180
+ looks the tool's pages do not set riding in the props `INERT_PROPS` lists. A gann square, a gann
3181
+ square fixed, a speed resistance fan, a pitchfan, the text and annotation tools, the marks and a
3182
+ table saved at `v: 2` paint as they were saved (`savedLook`) until their settings change. A host
3183
+ that writes drawings itself writes `v: 3`.
2884
3184
  - **Keys run through the registry.** Delete and Backspace remove the selection, Escape cancels a
2885
3185
  placement, disarms, or closes the inline editor, and Ctrl (or Cmd) with C and V copy and paste a
2886
3186
  drawing. Each resolves to a `chart.drawings.*` command, so your access policy gates the keyboard
@@ -2892,7 +3192,8 @@ What to know:
2892
3192
  a placed or dragged anchor onto the bar's own open, high, low or close; a locked drawing
2893
3193
  selects, takes the Delete and Clone a viewer asks for by name, and refuses a move, a resize, a
2894
3194
  text edit, the eraser and a Ctrl-drag copy; lock all suspends every edit, Delete and Clone
2895
- included, until it is released.
3195
+ included, until it is released. A right-click selects the drawing it lands on, so the menu that
3196
+ follows acts on it, and the handle under a mouse stands out.
2896
3197
 
2897
3198
  ## Extensions
2898
3199
 
@@ -1,4 +1,4 @@
1
- import { C as ChartSaveLoadAdapter } from '../resources-C0cYryO9.js';
1
+ import { C as ChartSaveLoadAdapter } from '../resources-Le6flcEn.js';
2
2
 
3
3
  /** The three template collections. */
4
4
  type RestTemplateKind = 'indicator' | 'drawing' | 'palette';