labicon.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. ``LabIcon`` - set up and render icons
  2. =====================================
  3. ``LabIcon`` is the icon class used by JupyterLab, and is part of the new
  4. icon system introduced in JupyterLab v2.0.
  5. How JupyterLab handles icons
  6. ----------------------------
  7. The @jupyterlab/ui-components package provides icons to the rest of
  8. JupyterLab, in the form of a set of ``LabIcon`` instances (currently
  9. about 80). All of the icons in the core JupyterLab packages are rendered
  10. using one of these ``LabIcon`` instances.
  11. Using the icons in your own code
  12. --------------------------------
  13. You can use any of JupyterLab icons in your own code via an ``import``
  14. statement. For example, to use ``jupyterIcon`` you would first do:
  15. .. code:: typescript
  16. import { jupyterIcon } from '@jupyterlab/ui-components';
  17. How to render an icon into a DOM node
  18. -------------------------------------
  19. Icons can be added as children to any ``div`` or ``span`` nodes using
  20. the ``icon.element(...)`` method (where ``icon`` is any instance of
  21. ``LabIcon``). For example, to render the Jupyter icon you could do:
  22. .. code:: typescript
  23. jupyterIcon.element({
  24. container: elem,
  25. height: '16px',
  26. width: '16px',
  27. marginLeft: '2px'
  28. });
  29. where ``elem`` is any ``HTMLElement`` with a ``div`` or ``span`` tag. As
  30. shown in the above example, the icon can be styled by passing CSS
  31. parameters into ``.element(...)``. Any valid CSS parameter can be used
  32. (one catch: snake case params do have to be converted to camel case:
  33. instead of ``foo-bar: '8px'``, you’d need to use ``fooBar: '8px'``.
  34. How to render an icon as a React component
  35. ------------------------------------------
  36. Icons can also be rendered using React. The ``icon.react`` parameter
  37. holds a standard React component that will display the icon on render.
  38. Like any React component, ``icon.react`` can be used in various ways.
  39. For example, here is how you would add the Jupyter icon to the render
  40. tree of another React component:
  41. .. code::
  42. public render() {
  43. return (
  44. <div className="outer">
  45. <div className="inner">
  46. <jupyterIcon.react tag="span" right="7px" top="5px" />
  47. "and here's a text node"
  48. </div>
  49. </div>
  50. );
  51. }
  52. Alternatively, you can just render the icon directly into any existing
  53. DOM node ``elem`` by using the ``ReactDOM`` module:
  54. .. code:: typescript
  55. ReactDOM.render(jupyterIcon.react, elem);
  56. If do you use ``ReactDOM`` to render, and if the ``elem`` node is ever
  57. removed from the DOM, you’ll first need to clean it up:
  58. .. code:: typescript
  59. ReactDOM.unmountComponentAtNode(elem);
  60. This cleanup step is not a special property of ``LabIcon``, but is
  61. instead needed for any React component that is rendered directly at the
  62. top level by ``ReactDOM``: failure to call ``unmountComponentAtNode``
  63. can result in a `memory
  64. leak <https://stackoverflow.com/a/48198011/425458>`__.
  65. How to create your own custom ``LabIcon``
  66. -----------------------------------------
  67. You can create your own custom icon by constructing a new instance of
  68. ``LabIcon``:
  69. .. code:: typescript
  70. export const fooIcon = new LabIcon({
  71. name: 'barpkg:foo',
  72. svgstr: '<svg>...</svg>'
  73. });
  74. where ``name`` should be of the form “your-pkg:icon-name”, and
  75. ``svgstr`` is the raw contents of your icon’s svg file.
  76. How to create a new ``LabIcon`` from an external svg file
  77. ---------------------------------------------------------
  78. Although you can copy-and-paste an svg directly into the ``LabIcon``
  79. constructor, the best practice is to keep the svg for each of your icons
  80. in its own separate svg file. You will need to have an ``svg.d.ts`` file
  81. at the root of your project’s ``src`` directory:
  82. .. code:: typescript
  83. // svg.d.ts
  84. declare module '*.svg' {
  85. const value: string;
  86. export default value;
  87. }
  88. You can then ``import`` the contents of an svg file:
  89. .. code:: typescript
  90. import fooSvgstr from 'path-to-your/foo.svg';
  91. export const fooIcon = new LabIcon({
  92. name: 'barpkg:foo',
  93. svgstr: fooSvgstr
  94. });
  95. Sync icon color to JupyterLab theme
  96. -----------------------------------
  97. .. raw:: html
  98. <em>Example svgs with class annotation can be found in <a href="https://github.com/jupyterlab/jupyterlab/tree/f0153e0258b32674c9aec106383ddf7b618cebab/packages/ui-components/style/icons">ui-components/style/icons</a></em>
  99. |
  100. | You can ensure that the colors of your custom ``LabIcon`` sync up to the colors of the current JuptyerLab theme by adding appropriate ``class`` annotations to each colored element of your icon's svg.
  101. |
  102. | In other words, each element of your svg that a ``fill="..."`` or a ``stroke="..."`` property should also have a ``class="jp-icon<whatever>"`` property.
  103. Available icon classes
  104. ^^^^^^^^^^^^^^^^^^^^^^
  105. .. raw:: html
  106. <em>Icon-related CSS classes are defined in <a href="https://github.com/jupyterlab/jupyterlab/blob/f0153e0258b32674c9aec106383ddf7b618cebab/packages/ui-components/style/icons.css">ui-components/style/icons.css</a></em>
  107. |
  108. | All colors shown are for the standard light/dark theme, mouse over for hex values.
  109. ``jp-iconX``: contrast to theme background
  110. """"""""""""""""""""""""""""""""""""""""""
  111. .. raw:: html
  112. <ul>
  113. <li>jp-icon0: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#111"/><title>#111</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#fff"/><title>#fff</title></svg></li>
  114. <li>jp-icon1: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#212121"/><title>#212121</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#fff"/><title>#fff</title></svg></li>
  115. <li>jp-icon2: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#424242"/><title>#424242</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#eee"/><title>#eee</title></svg></li>
  116. <li>jp-icon3: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#616161"/><title>#616161</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#bdbdbd"/><title>#bdbdbd</title></svg></li>
  117. <li>jp-icon4: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#757575"/><title>#757575</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#757575"/><title>#757575</title></svg></li>
  118. </ul>
  119. Most one-color icons in JupyterLab (including the sidebar and toolbar
  120. icons) are colored using the ``jp-icon3`` class.
  121. For light/dark themes, ``jp-icon0`` corresponds to the darkest/lighest
  122. background color, while ``jp-icon1`` is somewhat lighter/darker, and so
  123. forth.
  124. ``jp-icon-accentX``: match to theme background
  125. """"""""""""""""""""""""""""""""""""""""""""""
  126. .. raw:: html
  127. <ul>
  128. <li>jp-icon-accent0: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#fff"/><title>#fff</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#111"/><title>#111</title></svg></li>
  129. <li>jp-icon-accent1: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#fff"/><title>#fff</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#212121"/><title>#212121</title></svg></li>
  130. <li>jp-icon-accent2: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#eee"/><title>#eee</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#424242"/><title>#424242</title></svg></li>
  131. <li>jp-icon-accent3: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#bdbdbd"/><title>#bdbdbd</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#616161"/><title>#616161</title></svg></li>
  132. <li>jp-icon-accent4: <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#757575"/><title>#757575</title></svg> / <svg width="16" viewBox="0 0 1 1"><rect width="1" height="1" fill="#757575"/><title>#757575</title></svg></li>
  133. </ul>
  134. For light/dark themes, ``jp-icon-accent0`` corresponds to the
  135. lighest/darkest background color, while ``jp-icon-accent1`` is somewhat
  136. darker/lighter, and so forth.
  137. Adding classes to a one-color icon
  138. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  139. For most simple, one-color icons, it is desirable for the icon's color
  140. to strongly constrast with that of the application's background. You can
  141. acheive this using one of the ``jp-iconX`` classes.
  142. **Example: check icon**
  143. *svg source:*
  144. .. code:: html
  145. <svg xmlns="http://www.w3.org/2000/svg" width="100" viewBox="0 0 24 24">
  146. <path class="jp-icon3" fill="#616161" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
  147. </svg>
  148. *rendered icon:*
  149. .. raw:: html
  150. <svg xmlns="http://www.w3.org/2000/svg" width="100" viewBox="0 0 24 24">
  151. <path class="jp-icon3" fill="#616161" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
  152. </svg>
  153. Adding classes to a multi-colored icon
  154. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  155. For more complex icons, each element that needs to match the background
  156. should be annotated with a ``jp-icon-accentX`` class, while each element
  157. that needs to contrast with the background should be annotated with a
  158. ``jp-iconX`` class.
  159. **Example: close-circle icon**
  160. *svg source:*
  161. .. code:: html
  162. <svg xmlns="http://www.w3.org/2000/svg" width="100" viewBox="0 0 24 24">
  163. <circle class="jp-icon3" fill="#616161" cx="12" cy="12" r="11"/>
  164. <rect class="jp-icon-accent0" fill="#fff" height="18" width="2" x="11" y="3" transform="rotate(315, 12, 12)"/>
  165. <rect class="jp-icon-accent0" fill="#fff" height="18" width="2" x="11" y="3" transform="rotate(45, 12, 12)"/>
  166. </svg>
  167. *rendered icon:*
  168. .. raw:: html
  169. <svg xmlns="http://www.w3.org/2000/svg" width="100" viewBox="0 0 24 24">
  170. <circle class="jp-icon3" fill="#616161" cx="12" cy="12" r="11"/>
  171. <rect class="jp-icon-accent0" fill="#fff" height="18" width="2" x="11" y="3" transform="rotate(315, 12, 12)"/>
  172. <rect class="jp-icon-accent0" fill="#fff" height="18" width="2" x="11" y="3" transform="rotate(45, 12, 12)"/>
  173. </svg>
  174. Background
  175. ----------
  176. Icon handling in Jupyterlab
  177. ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  178. Pre JupyterLab 2.0, most icons were created using the icons-as-css-background
  179. pattern:
  180. - Set up the icon’s svg as a ``background-image`` in CSS:
  181. .. code:: css
  182. /* CSS */
  183. .jp-FooIcon {
  184. background-image: url('path-to-your/foo.svg');
  185. }
  186. - Add the icon to the DOM by constructing an otherwise empty DOM node
  187. with the appropriate class:
  188. .. code:: typescript
  189. // typescript
  190. const e = document.createElement('div');
  191. e.className = 'jp-FooIcon';
  192. document.body.append(e);
  193. What you end up with is a single DOM node that has the “foo” icon as a
  194. background image.
  195. Post JupyterLab 2.0, nearly all icons in core are now created using
  196. `LabIcon <https://github.com/jupyterlab/jupyterlab/blob/f0153e0258b32674c9aec106383ddf7b618cebab/packages/ui-components/src/icon/labicon.tsx>`__
  197. and the icons-as-inline-svg pattern:
  198. - Construct a new instance of LabIcon from the icon’s name and svg:
  199. .. code:: typescript
  200. // typescript
  201. // svgstr is the raw contents of an icon's svg file
  202. export const fooIcon = new LabIcon({
  203. name: 'barpkg:foo',
  204. svgstr: '<svg>...</svg>'
  205. });
  206. - Add the icon to the DOM using the appropriate property of your
  207. LabIcon instance (either LabIcon.element() to directly create a DOM
  208. node, or LabIcon.react to get the icon as a react component):
  209. .. code:: typescript
  210. // typescript
  211. const e = fooIcon.element();
  212. document.body.append(e);
  213. What you end up with is a DOM node (by default a ‘div’) that has an
  214. inline svg node as a child.
  215. ``background-image`` vs inline svg
  216. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  217. The big limitation of the old icon-as-css-background pattern is that svg
  218. images rendered as ``background-image`` are invisible to CSS. On the
  219. other hand, an icon rendered as an inline svg node is fully exposed to
  220. the CSS. This allows us to dynamically change icon styling as needed
  221. simply by modifying our CSS. Most importantly, this allows us to recolor
  222. icons according to Jupyterlab’s current theme.