Compare commits

...
Author SHA1 Message Date
github-actions[bot]andgithub-actions[bot] 1fa636bdd5 Version Packages (#2044)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-09 14:16:43 +02:00
Ken 44a75acb6b 🐛 className ble ikke riktig forwardet til period 2023-06-09 14:14:15 +02:00
Ken 550faee900 💄 Checkboard-pattern for transparent visning av tokens 2023-06-09 13:53:29 +02:00
Ken fbf016b3bd ✨ Forbedringer for Aksel.nav.no UI (#2043) 2023-06-09 13:05:59 +02:00
09fa503b98 initial template for PR (#2019)
* initial template for PR

* update template

* update template

* 📝 Oppdatert template

---------

Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
Co-authored-by: Ken <ken.aleksander@gmail.com>
2023-06-09 09:55:28 +02:00
Ken f5688485f5 ⬆️ Oppdatert Sanity 2023-06-08 18:43:14 +02:00
github-actions[bot]andgithub-actions[bot] 6385c4686e Version Packages (#2039)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-08 16:07:32 +02:00
Ken 30068dca3f 📝 La til jsdoc for skeleton-komponent 2023-06-08 16:03:27 +02:00
github-actions[bot]andgithub-actions[bot] 3aa04d2375 Version Packages (#2038)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-08 15:25:09 +02:00
Ken 91343563c9 🐛 Fikset markering av tekst internt i Skeleton-komponent 2023-06-08 15:21:52 +02:00
Ken d5c8112339 📝 Fikset typo i skeleton-docs 2023-06-08 15:02:24 +02:00
github-actions[bot]andgithub-actions[bot] e6cc9d1b4f Version Packages (#2031)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-08 14:49:16 +02:00
Ken db8c38a094 [Ny komponent] Skeleton (#1821) 2023-06-08 14:44:08 +02:00
Ken 35041e64eb Update README.md 2023-06-08 08:17:20 +02:00
Ken 690422d824 🐛 Fikset darkmode for skjemakomponenter 2023-06-07 20:10:28 +02:00
Ken b54bebd308 ⚡ Forbedret søk 2023-06-07 16:11:40 +02:00
Ken 8db194170c 🐛 Fikset chips.css bug etter merge 2023-06-07 15:45:00 +02:00
Ken 7b42f536aa 🎨 Oppdatert Chips-komponent (#2035) 2023-06-07 15:39:11 +02:00
Ken b2f796d681 💄 Text-subtle, icon-subtle til 700 nivå, form-description farger(#2036) 2023-06-07 15:22:02 +02:00
17d92c9ed5 add jsdoc (it's mostly copilot + some tweaks) (#2034)
* 📝 add jsdoc (it's mostly copilot + some tweaks)

* 😂 emojis

* 🏷️ add jsdoc for overridableComponents

* 🏷️ Oppdatert docgen for nestede komponenter

* 🎨 Oppdatert chat

* 🏷️ Dokumentert date-hooks

* 🏷️ Expansioncard-props

* 🏷️ Stepper.step jsdoc

* 🏷️ Tabs jsdoc

* 🏷️ Linkpaneltypes

* 🏷️ List jsdoc

* 🏷️ list jsdoc

* 🏷️ InternalHeader-docs

* 🏷️ jsdoc for dropdown

* 🏷️ Timeline jsdoc

---------

Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
Co-authored-by: Ken <ken.aleksander@gmail.com>
2023-06-07 14:19:34 +02:00
Ken 7bae5dce88 🎨 Fikset søketreff for CSS + overflow av ikonsøk-form 2023-06-06 15:43:38 +02:00
Ken 6aca0a4b6a 🎨 Data-tokens (#2032) 2023-06-06 13:49:31 +02:00
Ken 4f7fde22a3 🐛 Regex-fix for sanity-url er 2023-06-06 13:45:34 +02:00
Ken 0dad69a8df 💄 Fadein frontpage-cards 2023-06-05 22:34:37 +02:00
Julian Nymark c028f36e2b Indent prop added to accordion (#2027) 2023-06-05 19:38:44 +02:00
Ken 988fb36619 📝 Nettside-readme 2023-06-05 17:25:09 +02:00
Ken f61cd88627 📝 Oppdatert readme 2023-06-05 17:10:26 +02:00
github-actions[bot]andgithub-actions[bot] 7d62019a13 Version Packages (#2028)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-05 16:05:27 +02:00
Ken 83e3a1131a ⚰️ Fjernet kode for gamle pakker (#2029) 2023-06-05 15:58:53 +02:00
Ken 895bdc08e5 v4: Internal til Core, Datepicker ut av beta (#2026) 2023-06-05 15:05:31 +02:00
Ken 3c991e13d1 🐛 Fikset duplisert-id for komponent-eksempler 2023-06-05 14:50:42 +02:00
MaxandMaximilian Lloyd 0c24d57c6c 📝 Noen JSDoc eksempler (#2025)
Co-authored-by: Maximilian Lloyd <maximilian.oysta.lloyd@nav.no>
2023-06-05 09:14:48 +02:00
Ken 0f0041b71e 🎨 Forbedret ikonside og eksempel-navigering
🎨 Fungerende anchor-tag navigering for eksempler

🚚 Flyttet sections-kode i sidebar ut i egen hook

💄 Oppdatert tag
2023-06-05 08:52:21 +02:00
Ken da40cc405c ⬆️ Oppdatert sanity (#2021) 2023-06-02 20:31:14 +02:00
Ken c135cbe642 ⬆️ Oppdatert playwright-image til 1.33.0 versjon 2023-06-01 08:25:22 +02:00
Ken 2a2e9edbd7 ⬇️ Negradert playwright for å matche docker img-tag 2023-05-31 23:39:39 +02:00
Ken d22d6049e8 ⬆️ Oppdatert playwright-image til nyeste versjon 2023-05-31 23:26:17 +02:00
Ken f9bea26a29 🔥 Fjernet lenke til identitet da siden ikke lengre finnes 2023-05-31 23:17:17 +02:00
github-actions[bot]andgithub-actions[bot] 239017b07a Version Packages (#2018)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-05-31 15:39:05 +02:00
Julian Nymark 7615dbbb54 add dependency on postcss-value-parser (#2017) 2023-05-31 15:34:25 +02:00
Ken 4034eea298 🐛 Fikset release av stylelint 2023-05-31 15:03:16 +02:00
github-actions[bot]andgithub-actions[bot] 68501b4c8a Version Packages (#2015)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-05-31 14:29:19 +02:00
61c4114214 [WIP] aksel stylelint (#1973)
* working stylelint config + test rule

this commit is a good "base" for developing future stylelint rules

* merge ideas (sortof)

* delete test-rule + add URL to readme section

* flatten json object

* bundle token files at build time

* update lock file deps

* package distribution & version in error message

* rule for internal tokens

* rule for class name override

* remove config props

* fix: emit multiple errors for nodes in postcss-value-parser

* adjust error messages

* some tests

* final tests

* refactor

* no more regex

* update README.md

* update README.md (again)

* readme

* readme and usage example for aksel-design-token-exists

* move README of rule into top-level README

* update README

* update README

* move sources into /src, bookkeeping

* add aksel-stylelint to changeset.fixed

* set exports correctly (exposes ./recommended)

* bookkeeping, cleanup, refactor, remove test files

* Update README.md

* changeset

* fix urls

* update test for aksel-design-token-exists to cover all token files

* add more granular error catching

* cleanup, improve error message

* update tests + fix code that broke tests

* add rule: deprecate classes

* adjust aksel-design-token-exists

* adjust test for no-deprecated-classes

* refactor design-token-exists

* update README

* 📝 update README

* update readme

* refactor: split rules into smaller rules

* fix tests (deduplicate from refactor), fix plugin too

* fix meta name / ruleName -> ruleNamePackage refactor

* set internal dependencies (build time)

* set internal dependencies (build time)

* when building stylelint, always pull latest css & token files

* new lock

* test cache-busting

* ignore some lint rules

* deduplicate rulename

* bring back caching in ci.yml

* 📝 Oppdatert Package.json docs

* more helpful error messages

* 📝 Updated readme

* 📝 Updated prefixes for rules in readme

* 📝 Formateringsfeil i readme

* refactor ruleNames (shorter and better!)

* update one more rule name (I forgor)

* refactor names again (must have namespace)

* 🐛 Fikset intern bruk av lint-regler

* ⬆️ yarn lock sync

---------

Co-authored-by: Halvor Haugan <halvor.haugan@nav.no>
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
Co-authored-by: Ken <ken.aleksander@gmail.com>
2023-05-31 14:22:41 +02:00
Halvor HauganandKen b958d41a20 ✨ Tag: ny variant "moderate" (#2010)
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
2023-05-31 13:53:30 +02:00
Ken c3905aa2f8 🎨 linetermination fix for windows (#2014) 2023-05-31 13:53:00 +02:00
Ken 812a2347a0 ♿ Mindre uu-fiks for ikonside 2023-05-31 10:18:15 +02:00
Ken deb1c151bb Update README.md 2023-05-30 15:18:26 +02:00
Ken 784d17165d ♻️ Ikonside bruker nå CopyButton 2023-05-30 15:07:18 +02:00
Ken 1a894829f0 🎨 Search: Custom-button eksempel for aksel 2023-05-26 14:04:59 +02:00
Halvor Haugan e06a76b5c5 🐛 aksel-icons copyfiles-kommandoen fungerer nå på Win/Unix (#2007) 2023-05-25 22:35:49 +02:00
github-actions[bot]andgithub-actions[bot] 18d6f63e3e Version Packages (#2006)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-05-25 15:12:17 +02:00
Ken 4953e6725e 🐛 Ignore figma-plugin 2023-05-25 14:53:43 +02:00
Christian Skrøvseth 5533fbd5a3 Migrate CopyButton from deprecated to modern clipboard (#2005) 2023-05-25 14:40:22 +02:00
Ken 2c54cd077b 🎨 Icon-plugin (#1997) 2023-05-25 13:38:37 +02:00
Ken c84efa5ee9 🐛 Disable chromatic-snapshot av flaky button-story 2023-05-25 13:08:13 +02:00
Ken 9f3bcb8974 🐛 Endret rekkefølge på timeline-eksempler 2023-05-25 13:03:55 +02:00
github-actions[bot]andgithub-actions[bot] c8375ba46f Version Packages (#2002)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-05-25 12:36:22 +02:00
Ken 288cef591a Timeline viser popover på hover (#1995) 2023-05-25 12:25:26 +02:00
Ken aa3b4c22d6 🎨 Mulighet for manuell sortering av elementer i grunnleggende-sidebar 2023-05-24 18:26:38 +02:00
github-actions[bot]andgithub-actions[bot] 46af5defd9 Version Packages (#2001)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-05-24 15:32:35 +02:00
Ken 30eee0dac4 🐛 Fikset htmlSize-prop for <Search /> (#2000) 2023-05-24 14:36:34 +02:00
Ken 76b3a65572 Update README.md 2023-05-23 12:39:10 +02:00
1003 changed files with 12631 additions and 16937 deletions

No files matched your search

-3
View File
@@ -31,10 +31,7 @@ Alle base-pakkene våre har `fixed versjonering`. Dette tilsier at en bump på e
"@navikt/ds-react",
"@navikt/ds-css",
"@navikt/aksel-icons",
"@navikt/ds-icons",
"@navikt/ds-tokens",
"@navikt/ds-tailwind",
"@navikt/ds-css-internal",
"@navikt/ds-react-internal",
"@navikt/ds-codemod"
```
+2 -5
View File
@@ -8,19 +8,16 @@
"@navikt/ds-css",
"@navikt/ds-tokens",
"@navikt/ds-tailwind",
"@navikt/ds-css-internal",
"@navikt/ds-react-internal",
"@navikt/ds-codemod",
"@navikt/aksel-icons",
"@navikt/aksel",
"@navikt/ds-icons"
"@navikt/aksel-stylelint"
]
],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["shadow-dom", "aksel.nav.no", "@navikt/ds-navno"],
"ignore": ["shadow-dom", "aksel.nav.no", "aksel-icons-figma-plugin"],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"updateInternalDependents": "always"
+17
View File
@@ -0,0 +1,17 @@
### :memo: PR Checklist
<!-- Remove non-relevant fields -->
- [ ] :sparkles: New component? Add CSS-mappings to `@navikt/core/css/config/_mappings.js`.
- [ ] :wastebasket: Are you deprecating a CSS class? (are you removing the last known reference to a CSS class?). Add it to `@navikt/aksel-stylelint/src/deprecations.ts` with a suitable description.
- [ ] :balance_scale: Is the feature/component/code sufficiently complex to warrant tests? Add some unit-tests :test_tube:
- [ ] :balance_scale: Does the feature/component add some complex user-interactions? Consider adding some [interaction-tests with storybook](https://storybook.js.org/docs/react/writing-tests/interaction-testing) :test_tube:
- [ ] :boom: Are there breaking changes? Consider adding a codemod for easier migration.
- [ ] :test_tube: Are all variations and cases shown in the storybook stories? Stories are used for [visual regression testing](https://www.chromatic.com/docs/), so make sure they are complete.
- [ ] Run `yarn changeset` for version and changelog generation
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
playwright:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.30.0-focal
image: mcr.microsoft.com/playwright:v1.33.0-focal
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
name: Smoketest Aksel
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.30.0-focal
image: mcr.microsoft.com/playwright:v1.33.0-focal
steps:
- uses: actions/setup-node@v3
with:
-42
View File
@@ -1,42 +0,0 @@
name: Update Icons
on:
# schedule:
# - cron: 0 0 * * *
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14
- name: Node-modules cache
uses: actions/cache@v3
id: node-cache
with:
path: "**/node_modules"
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: install
if: steps.node-cache.outputs.cache-hit != 'true'
run: yarn install
- name: postinstall
if: steps.node-cache.outputs.cache-hit == 'true'
run: yarn postinstall
- name: Update Icons
run: yarn workspace @navikt/ds-icons update
env:
FIGMA_TOKEN: ${{ secrets.FIGMA_IKONER_API }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GIT_REPO }}
commit-message: "Ikoner synket fra figma"
branch: figma-icons-sync
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: false
delete-branch: true
title: "Ikonsynk Figma"
-39
View File
@@ -1,39 +0,0 @@
name: Update tokens
on:
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14
- name: Node-modules cache
uses: actions/cache@v3
id: node-cache
with:
path: "**/node_modules"
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: install
if: steps.node-cache.outputs.cache-hit != 'true'
run: yarn install
- name: postinstall
if: steps.node-cache.outputs.cache-hit == 'true'
run: yarn postinstall
- name: Update tokens
run: yarn workspace @navikt/ds-tokens update
env:
FIGMA_TOKEN: ${{ secrets.FIGMA_IKONER_API }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: figma-tokens-sync
delete-branch: true
title: "Tokens sync Figma"
commit-message: "Tokens synket fra figma"
committer: GitHub <noreply@github.com>
signoff: false
+2 -10
View File
@@ -6,19 +6,11 @@ import { Meta, Canvas } from "@storybook/addon-docs";
[Dokumentasjon](https://aksel.nav.no/komponenter)
### Core
```bash
yarn add @navikt/ds-react @navikt/ds-css
```
### Interne-flater
```bash
yarn add @navikt/ds-react-internal @navikt/ds-css-internal
```
### Ikoner
## Ikoner
[Dokumentasjon](https://aksel.nav.no/ikoner)
@@ -26,7 +18,7 @@ yarn add @navikt/ds-react-internal @navikt/ds-css-internal
yarn add @navikt/aksel-icons
```
### Bruk
## Bruk
```jsx
import { Heading } from "@navikt/ds-react";
-2
View File
@@ -1,6 +1,4 @@
import { RouterContext } from "next/dist/shared/lib/router-context";
import "@navikt/ds-css/index.css";
import "@navikt/ds-css-internal/index.css";
import "./layout.css";
export const parameters = {
+22
View File
@@ -1,5 +1,27 @@
# @navikt/aksel-icons
## 4.1.3
## 4.1.2
## 4.1.1
## 4.1.0
## 4.0.0
## 3.4.2
## 3.4.1
## 3.4.0
## 3.3.1
## 3.3.0
## 3.2.4
## 3.2.3
### Patch Changes
+5
View File
@@ -24,6 +24,11 @@ fs.writeFileSync(
`const metadata = ${JSON.stringify(metadata)};\n\n module.exports = metadata;`
);
fs.writeFileSync(
path.resolve(__dirname, "../dist/metadata.mjs"),
`const metadata = ${JSON.stringify(metadata)};\n\n export default metadata;`
);
fs.writeFileSync(
path.resolve(__dirname, "../dist/metadata.d.ts"),
`export type AkselIcon = {
@@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
!src
!*.d.ts
@@ -0,0 +1,22 @@
![](/src/assets/gh-cover.png)
# Aksel Icons plugin
Pluginen gir deg mulighet til å se gjennom og hente ut alle ikonene i fra ikonpakken `@navikt/aksel-icons`. Du slipper da å hente nye oppdateringer fra Figma Community.
Referer til [ikon-dokumentasjonen](https://aksel.nav.no/ikoner) for å se alle ikonene.
Har du ønsker om nye ikoner, eller ønsker å bidra med å lage nye, lag et issue på [GitHub-repoet for designsystemet](https://github.com/navikt/aksel).
## Quickstart
- `yarn dev` for development
- `yarn build` for production-build
### Test with Figma
- Open `Figma` -> `Plugins` -> `Development` -> `Import plugin from manifest...` and choose `manifest.json` file from this repo.
### Publish to Figma
- Open `Figma` -> `Plugins` -> `Find more plugins` -> `Publish new versions`
(requires publish-access)
@@ -0,0 +1,10 @@
{
"name": "Aksel Icons",
"id": "1221057403873975172",
"api": "1.0.0",
"main": "dist/plugin.js",
"ui": "dist/index.html",
"capabilities": [],
"enableProposedApi": false,
"editorType": ["figma", "figjam"]
}
@@ -0,0 +1,35 @@
{
"name": "aksel-icons-figma-plugin",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite -c ./vite.config.ui.ts",
"build:icon-plugin": "tsc && npm run build:ui && npm run build:plugin",
"build:ui": "vite build -c ./vite.config.ui.ts --emptyOutDir",
"build:plugin": "vite build -c ./vite.config.plugin.ts",
"preview": "vite preview"
},
"dependencies": {
"@navikt/ds-css": "*",
"@navikt/ds-react": "*",
"fuse.js": "^6.6.2",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@figma/plugin-typings": "^1.62.0",
"@svgr/core": "^6.5.1",
"@types/node": "^18.15.11",
"@types/postcss-url": "^10.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@vitejs/plugin-react": "^3.1.0",
"postcss": "^8.4.0",
"postcss-url": "^10.1.3",
"typescript": "^4.8.0",
"vite": "^4.2.0",
"vite-plugin-singlefile": "^0.13.3",
"vite-plugin-svgr": "^2.4.0"
}
}
@@ -0,0 +1,31 @@
/* eslint-disable import/no-anonymous-default-export */
import fs from "fs";
import { Plugin } from "vite";
function svgToDataURL(svgStr: string) {
const encoded = encodeURIComponent(svgStr)
.replace(/'/g, "%27")
.replace(/"/g, "%22");
const header = "data:image/svg+xml,";
const dataUrl = header + encoded;
return dataUrl;
}
export default function (): Plugin {
return {
name: "vite-inline-svg",
enforce: "pre",
async load(id) {
const [path, query] = id.split("?", 2);
if (!path.endsWith(".svg")) return;
if (query !== "inline") return;
const svg = await fs.promises.readFile(path, "utf-8");
return `export default "${svgToDataURL(svg)}"`;
},
};
}
@@ -0,0 +1,50 @@
import { createFilter, FilterPattern } from "@rollup/pluginutils";
import type { Config } from "@svgr/core";
import fs from "fs";
import type { Plugin } from "vite";
import { transformWithEsbuild } from "vite";
export interface ViteSvgrOptions {
svgrOptions?: Config;
esbuildOptions?: Parameters<typeof transformWithEsbuild>[2];
exclude?: FilterPattern;
include?: FilterPattern;
}
export default function viteSvgr({
svgrOptions,
esbuildOptions,
include = "**/*.svg?component",
exclude,
}: ViteSvgrOptions = {}): Plugin {
const filter = createFilter(include, exclude);
return {
name: "vite-svgr-component",
async transform(code, id) {
if (filter(id)) {
const { transform } = await import("@svgr/core");
const svgCode = await fs.promises.readFile(
id.replace(/\?.*$/, ""),
"utf8"
);
const componentCode = await transform(svgCode, svgrOptions, {
filePath: id,
caller: { previousExport: null },
});
const res = await transformWithEsbuild(componentCode, id, {
loader: "jsx",
...esbuildOptions,
});
return {
code: res.code,
map: null,
};
}
},
};
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 170 170" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.07318 54.5734C-0.692218 51.806 -0.690888 47.3204 2.07614 44.5546L38.6019 8.04512C38.7787 7.8684 38.9576 7.69433 39.1387 7.52295L39.1205 7.50476C42.7235 3.90124 47.1588 1.63753 51.8075 0.71364C53.8316 0.243049 55.9182 1.07479e-05 58.0297 1.01387e-05L142.517 0C157.695 5.55246e-06 170 12.3065 170 27.4874V111.958C170 113.916 169.791 115.852 169.386 117.737C168.522 122.523 166.241 127.103 162.542 130.803L162.533 130.794C162.342 130.997 162.148 131.197 161.95 131.395L125.425 167.925C122.659 170.692 118.174 170.692 115.408 167.925C112.642 165.158 112.642 160.673 115.408 157.906L151.933 121.376C153.698 119.61 154.917 117.4 155.48 115.008C155.999 111.779 155.014 108.355 152.525 105.866L64.1955 17.5236C61.632 14.9597 58.0865 13.9765 54.7698 14.574C52.4605 15.1572 50.3292 16.3547 48.6162 18.0669L12.0905 54.5764C9.32349 57.3422 4.83857 57.3409 2.07318 54.5734ZM80.8759 14.1688L155.833 89.1374V27.4874C155.833 20.1317 149.871 14.1688 142.517 14.1688L80.8759 14.1688Z" fill="#004367"/>
<path d="M2.07466 167.925C-0.691554 165.158 -0.691554 160.673 2.07466 157.906L65.8247 94.1468C68.5909 91.3801 73.0758 91.3801 75.842 94.1468C78.6082 96.9134 78.6082 101.399 75.842 104.166L12.092 167.925C9.32579 170.692 4.84087 170.692 2.07466 167.925Z" fill="#004367"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,21 @@
/* eslint-disable no-restricted-globals */
/* eslint-disable no-undef */
import * as Networker from "monorepo-networker";
import { NetworkMessages } from "@common/network/messages";
import { NetworkSide } from "@common/network/sides";
export const initializeNetwork = Networker.createInitializer({
messagesRegistry: NetworkMessages.registry,
initTransports: function (register) {
register(NetworkSide.PLUGIN, NetworkSide.UI, (message) => {
// @ts-ignore
figma.ui.postMessage(message);
});
register(NetworkSide.UI, NetworkSide.PLUGIN, (message) => {
// @ts-ignore
parent.postMessage({ pluginMessage: message }, "*");
});
},
});
@@ -0,0 +1,21 @@
import { CreateRectMessage } from "@common/network/messages/CreateRectMessage";
import { HelloMessage } from "@common/network/messages/HelloMessage";
import { PingMessage } from "@common/network/messages/PingMessage";
import { NetworkSide } from "@common/network/sides";
import * as Networker from "monorepo-networker";
export namespace NetworkMessages {
export const registry = new Networker.MessageTypeRegistry();
export const PING = registry.register(new PingMessage("ping"));
export const HELLO_PLUGIN = registry.register(
new HelloMessage(NetworkSide.PLUGIN)
);
export const HELLO_UI = registry.register(new HelloMessage(NetworkSide.UI));
export const CREATE_RECT = registry.register(
new CreateRectMessage("create-rect")
);
}
@@ -0,0 +1,42 @@
/* eslint-disable no-undef */
import { NetworkSide } from "@common/network/sides";
import * as Networker from "monorepo-networker";
interface Payload {
width: number;
height: number;
}
export class CreateRectMessage extends Networker.MessageType<Payload> {
public receivingSide(): Networker.Side {
return NetworkSide.PLUGIN;
}
public handle(payload: Payload, from: Networker.Side): void {
// @ts-ignore
if (figma.editorType === "figma") {
// @ts-ignore
const rect = figma.createRectangle();
rect.x = 0;
rect.y = 0;
rect.name = "Plugin Rectangle # " + Math.floor(Math.random() * 9999);
rect.fills = [
{
type: "SOLID",
color: {
r: Math.random(),
g: Math.random(),
b: Math.random(),
},
},
];
rect.resize(payload.width, payload.height);
// @ts-ignore
figma.currentPage.appendChild(rect);
// @ts-ignore
figma.viewport.scrollAndZoomIntoView([rect]);
// @ts-ignore
figma.closePlugin();
}
}
}
@@ -0,0 +1,19 @@
import * as Networker from "monorepo-networker";
interface Payload {
text: string;
}
export class HelloMessage extends Networker.MessageType<Payload> {
constructor(private side: Networker.Side) {
super("hello-" + side.getName());
}
receivingSide(): Networker.Side {
return this.side;
}
handle(payload: Payload, from: Networker.Side) {
console.log(`${from.getName()} said "${payload.text}"`);
}
}
@@ -0,0 +1,17 @@
import * as Networker from "monorepo-networker";
import { NetworkSide } from "@common/network/sides";
interface Payload {}
type Response = string;
export class PingMessage extends Networker.MessageType<Payload, Response> {
receivingSide(): Networker.Side {
return NetworkSide.PLUGIN;
}
handle(payload: Payload, from: Networker.Side): string {
console.log(from.getName(), "has pinged us!");
return `Pong, ${from.getName()}!`;
}
}
@@ -0,0 +1,24 @@
/* eslint-disable no-undef */
import * as Networker from "monorepo-networker";
export namespace NetworkSide {
export const PLUGIN = Networker.Side.register(
new Networker.Side<MessageEvent<any>>("Plugin", {
// @ts-ignore
attachListener: (callback) => figma.ui.on("message", callback),
// @ts-ignore
detachListener: (callback) => figma.ui.off("message", callback),
})
);
export const UI = Networker.Side.register(
new Networker.Side("UI", {
shouldHandle: (event) => event.data?.pluginId != null,
messageGetter: (event) => event.data.pluginMessage,
attachListener: (callback) =>
window.addEventListener("message", callback),
detachListener: (callback) =>
window.removeEventListener("message", callback),
})
);
}
@@ -0,0 +1,48 @@
/* eslint-disable no-undef */
figma.showUI(__html__, { width: 480, height: 600 });
figma.ui.onmessage = (msg) => {
if (msg.type === "create-icon") {
const nodes = [];
const icon = figma.createNodeFromSvg(msg.svg);
icon.name = msg.name;
icon.resize(msg.size, msg.size);
nodes.push(icon);
figma.currentPage.appendChild(icon);
figma.viewport.scrollAndZoomIntoView(nodes);
figma.ui.postMessage({
type: "create-icon",
message: `Created ${msg.name} icon}`,
});
}
};
// https://github.com/figma/plugin-samples#icon-drag-and-drop
figma.on("drop", (event) => {
const { files, node } = event;
if (files.length > 0 && files[0].type === "image/svg+xml") {
files[0].getTextAsync().then((text) => {
const newNode = figma.createNodeFromSvg(text);
newNode.name = `${files[0].name.replace(".svg", "")}Icon`;
newNode.resize(24, 24);
// We can only append page nodes to documents
if ("appendChild" in node && node.type !== "DOCUMENT") {
node.appendChild(newNode);
}
newNode.x = event.x;
newNode.y = event.y;
figma.currentPage.selection = [newNode];
});
return false;
}
});
@@ -0,0 +1,193 @@
import { Heading, Search, ToggleGroup } from "@navikt/ds-react";
import Fuse from "fuse.js";
import { useEffect, useMemo, useState } from "react";
import * as Icons from "../../../";
import meta from "../../../dist/metadata";
import "./app.css";
import { categorizeIcons, getFillIcon } from "./utils";
const fuseStroke = new Fuse(
Object.values(meta).filter((x) => x.variant.toLowerCase() === "stroke"),
{
threshold: 0.2,
keys: [
{ name: "name", weight: 3 },
{ name: "category", weight: 2 },
{ name: "sub_category", weight: 2 },
{ name: "keywords", weight: 3 },
{ name: "variant", weight: 1 },
],
shouldSort: false,
}
);
const fuseFill = new Fuse(getFillIcon(Object.values(meta)), {
threshold: 0.2,
keys: [
{ name: "name", weight: 3 },
{ name: "category", weight: 2 },
{ name: "sub_category", weight: 2 },
{ name: "keywords", weight: 3 },
{ name: "variant", weight: 1 },
],
shouldSort: false,
});
const App = () => {
const [query, setQuery] = useState("");
const [toggle, setToggle] = useState<"stroke" | "fill">("stroke");
const [strokeIcons] = useState(
Object.values(meta).filter((x) => x.variant.toLowerCase() === "stroke")
);
const [fillIcons] = useState(getFillIcon(Object.values(meta)));
const categories = useMemo(() => {
if (toggle === "fill") {
return categorizeIcons(
query
? fuseFill.search(query).map((result) => result.item as any)
: fillIcons
);
}
return categorizeIcons(
query
? fuseStroke.search(query).map((result) => result.item as any)
: strokeIcons
);
}, [toggle, query, strokeIcons, fillIcons]);
const onCreate = (id: string, name: string) => {
let svg = document.getElementById(id)?.outerHTML;
let size = 24;
// eslint-disable-next-line no-restricted-globals
parent.postMessage(
{
pluginMessage: {
type: "create-icon",
svg,
size,
name,
},
},
"*"
);
};
useEffect(() => {
const dragEvent = (e) => {
// Don't proceed if the item was dropped inside the plugin window.
if (e.view.length === 0) {
return;
}
const file = new File([e.target.innerHTML], `${e.target.id}.svg`, {
type: "image/svg+xml",
});
window.parent.postMessage(
{
pluginDrop: {
clientX: e.clientX,
clientY: e.clientY,
files: [file],
name: e.target.id,
},
},
"*"
);
};
const icons = document.getElementsByClassName("icon-classname");
for (const icon of icons) {
icon.addEventListener("dragend", dragEvent);
}
return () => {
for (const icon of icons) {
icon.removeEventListener("dragend", dragEvent);
}
};
}, [categories]);
return (
<main tabIndex={-1} className="wrapper">
<form onSubmit={(e) => e.preventDefault()} className="form">
<div className="form-togglegroup">
<ToggleGroup
value={toggle}
onChange={(v) => setToggle(v as any)}
variant="neutral"
>
<ToggleGroup.Item value="stroke">Stroke</ToggleGroup.Item>
<ToggleGroup.Item value="fill">Fill</ToggleGroup.Item>
</ToggleGroup>
</div>
<div className="form-search">
<Search
variant="simple"
label="Ikonsøk"
style={{ border: "none" }}
placeholder="Søk"
autoComplete="off"
onChange={setQuery}
value={query}
clearButton={false}
/>
</div>
</form>
<div className="categories">
{categories.map((cat) => {
return (
<div key={cat.category}>
<Heading level="2" size="small" spacing>
{cat.category}
</Heading>
<div className="sub-categories">
{cat.sub_categories.map((sub) => {
return (
<div key={sub.sub_category}>
<Heading level="3" size="xsmall" className="sub-heading">
{sub.sub_category}
</Heading>
<div className="icons-wrapper">
{sub.icons.map((i) => {
const T = Icons[`${i.id}Icon`];
if (T === undefined) {
console.log(i);
return null;
}
return (
<button
key={i.id}
id={i.id}
onClick={() => {
onCreate(`icon-id-${i.id}`, `${i.id}Icon`);
}}
draggable="true"
className="icon-classname icon-button"
>
<T
font-size="2rem"
title={i.id}
id={`icon-id-${i.id}`}
/>
</button>
);
})}
</div>
</div>
);
})}
</div>
</div>
);
})}
</div>
</main>
);
};
export default App;
@@ -0,0 +1,79 @@
@import "@navikt/ds-css";
.wrapper {
background-color: var(--a-bg-default);
}
.form {
border-bottom: 1px solid var(--a-border-subtle);
position: sticky;
top: 0;
z-index: 20;
display: flex;
align-items: center;
height: fit-content;
width: 100%;
gap: 1rem;
padding-block: 0.5rem;
padding-inline: 1rem;
background-color: var(--a-bg-default);
}
.form-togglegroup {
min-width: 10rem;
}
.form-search {
display: flex;
gap: 0.5rem;
align-items: center;
width: 100%;
}
.categories {
display: grid;
width: 100%;
place-content: start;
gap: 2rem;
padding: 1.5rem;
}
.sub-categories {
display: grid;
width: 100%;
gap: 0.5rem;
}
.sub-heading {
color: var(--a-text-subtle);
margin-bottom: 0.25rem;
}
.icons-wrapper {
gap: 0.125rem;
display: flex;
flex-wrap: wrap;
}
.icon-button {
min-height: 3rem;
min-width: 3rem;
border-radius: 2px;
display: grid;
place-content: center;
background-color: var(--a-surface-default);
cursor: pointer;
border: none;
}
.icon-button:hover {
background-color: var(--a-surface-hover);
}
.icon-button:active {
background-color: var(--a-surface-neutral-subtle-hover);
}
.icon-button:focus-visible {
outline: 2px solid var(--a-border-focus);
}
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Aksel icons</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
@@ -0,0 +1,9 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
@@ -0,0 +1,56 @@
import meta from "@navikt/aksel-icons/metadata";
const subCategorizeIcons = (
icons: typeof meta[1][]
): { sub_category: string; icons: typeof meta[1][] }[] => {
const categories: { sub_category: string; icons: typeof meta[1][] }[] = [];
for (const icon of icons) {
const i = categories.findIndex(
({ sub_category }) => icon.sub_category === sub_category
);
i !== -1
? categories[i].icons.push(icon)
: categories.push({ sub_category: icon.sub_category, icons: [icon] });
}
return categories.sort((a, b) =>
a.sub_category.localeCompare(b.sub_category)
);
};
export const categorizeIcons = (
icons: typeof meta[1][]
): {
category: string;
sub_categories: { sub_category: string; icons: typeof meta[1][] }[];
}[] => {
const categories: {
category: string;
icons: typeof meta[1][];
}[] = [];
for (const icon of icons) {
const i = categories.findIndex(
({ category }) => icon.category === category
);
i !== -1
? categories[i].icons.push(icon)
: categories.push({ category: icon.category, icons: [icon] });
}
return categories
.sort((a, b) => a.category.localeCompare(b.category))
.map((x) => ({ ...x, sub_categories: subCategorizeIcons(x.icons) }));
};
const noFill = (icon: typeof meta[1], icons: typeof meta[1][]) => {
const foundFill = icons.find(
(x) => x.name.endsWith("Fill") && x.name.replace("Fill", "") === icon.name
);
return !foundFill;
};
export const getFillIcon = (icons: typeof meta[1][]) => {
return icons.filter(
(x, _, z) => x.variant.toLowerCase() === "fill" || noFill(x, z)
);
};
+30
View File
@@ -0,0 +1,30 @@
/// <reference types="vite/client" />
declare module "*.svg?component" {
import * as React from "react";
const ReactComponent: React.FunctionComponent<
React.ComponentProps<"svg"> & { title?: string }
>;
export default ReactComponent;
}
declare module "**/metadata.mjs" {
export type AkselIcon = {
id: string;
name: string;
category: string;
sub_category: "Time";
keywords: string[];
variant: "stroke" | "fill";
updated_at: Date;
created_at: Date;
};
declare const metadata: {
[iconId: string]: AkselIcon;
};
export default metadata;
}
@@ -0,0 +1,30 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "CommonJS",
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": false,
"noEmit": true,
"jsx": "react-jsx",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"rootDir": ".",
"baseUrl": ".",
"outDir": "dist/",
"sourceMap": false,
"noImplicitAny": false,
"types": ["@figma/plugin-typings"]
},
"include": [
"src/**/*.d.ts",
"src/**/*.d.ts",
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.js",
"src/**/*.jsx"
],
"exclude": ["src/common/**/*"]
}
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": [
"vite.config.plugin.ts",
"vite.config.ui.ts",
"./scripts/vite/*.ts"
]
}
@@ -0,0 +1,17 @@
import path from "path";
import { defineConfig } from "vite";
import { viteSingleFile } from "vite-plugin-singlefile";
export default defineConfig({
plugins: [viteSingleFile()],
build: {
lib: {
name: "Aksel Icons",
entry: path.resolve(__dirname, "./src/plugin/plugin.ts"),
fileName: "plugin",
formats: ["es"],
},
emptyOutDir: false,
outDir: path.resolve(__dirname, "./dist"),
},
});
@@ -0,0 +1,25 @@
import { defineConfig } from "vite";
import path from "path";
import { viteSingleFile } from "vite-plugin-singlefile";
import react from "@vitejs/plugin-react";
import inlineSvg from "./scripts/vite/vite-inline-svg";
import svgComponent from "./scripts/vite/vite-svgr-component";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), svgComponent(), inlineSvg(), viteSingleFile()],
root: path.resolve(__dirname, "./src/ui/"),
build: {
outDir: path.resolve(__dirname, "./dist"),
rollupOptions: {
input: {
ui: path.relative(__dirname, "./src/ui/index.html"),
},
output: {
entryFileNames: "[name].js",
},
},
},
});
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-icons",
"version": "3.2.3",
"version": "4.1.3",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/ikoner",
"repository": {
@@ -53,7 +53,7 @@
"scripts": {
"create-icons": "svgr --silent --index-template config/index-template.js --out-dir src icons",
"copy-util": "copyfiles util/* src",
"copy-svg": "copyfiles -f icons/*.svg dist/svg/",
"copy-svg": "copyfiles -f 'icons/*.svg' dist/svg/",
"copy": "yarn copy-util && yarn copy-svg",
"update-metadata": "node config/metadata.js",
"build": "yarn copy && yarn create-icons && concurrently \"tsc\" \"tsc -p tsconfig.esm.json\" && node config/cleanTypes.js && yarn update-metadata",
+1
View File
@@ -0,0 +1 @@
/dist
+36
View File
@@ -0,0 +1,36 @@
# @navikt/aksel-stylelint
## 4.1.3
## 4.1.2
## 4.1.1
## 4.1.0
### Minor Changes
- [#2035](https://github.com/navikt/aksel/pull/2035) [`7b42f536a`](https://github.com/navikt/aksel/commit/7b42f536aa90c1b5dbe2b19f1bbe292701546420) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :tada: Oppdatert Chips
- Toggle Chips har nå varianter: neutral og action
- Toggle Chips har nå en ny prop: `checkmark` som slår av/på checkmark ved selected-state
## 4.0.0
## 3.4.2
### Patch Changes
- [#2017](https://github.com/navikt/aksel/pull/2017) [`7615dbbb5`](https://github.com/navikt/aksel/commit/7615dbbb54c7c96e2252366188547b27b2ac1142) Thanks [@JulianNymark](https://github.com/JulianNymark)! - add missing dependency
## 3.4.1
### Patch Changes
- :bug: Stylelint hotfix, inkluderer nå dist-mappe (kanskje..)
## 3.4.0
### Minor Changes
- [#1973](https://github.com/navikt/aksel/pull/1973) [`61c411421`](https://github.com/navikt/aksel/commit/61c4114214841ec42f48e1abd0d72d2a42d265ab) Thanks [@JulianNymark](https://github.com/JulianNymark)! - add stylelint plugin
+173
View File
@@ -0,0 +1,173 @@
# Aksel stylelint rules & plugins
This stylelint plugin is useful when working with the [Aksel design system](https://aksel.nav.no/).
It is designed to be useful for both _internal_ and _external_ developers, so _everyone_ should install this 🙌.
> **Warning**
> The version of this plugin **_MUST MATCH_** the version of the other design system packages used in your project for the linting to make sense!
> Otherwise you are very likely to get _incorrect_ errors that tell you to use the wrong token names.
# Install
```bash
yarn add -D @navikt/aksel-stylelint
npm install -D @navikt/aksel-stylelint
```
### How to configure
It should be sufficient for most cases to extend the recommended defaults.
```js
"stylelint": {
"extends": [
...
"@navikt/aksel-stylelint/recommended"
],
...
}
```
## aksel/design-token-exists
Makes sure all referenced CSS-variables with prefix `--a-` or `--ac-` exists in Aksels token-collection. As a side-effect Aksel reserves these prefixes for its design-tokens.
❌ Incorrect:
```css
html {
--a-my-own-color-bg-hover: #f2f2f2;
^^^^^^^^^^^^^^^^^^^^^^^^^
background-color: var(--a-my-own-color-bg-hover);
^^^^^^^^^^^^^^^^^^^^^^^^^
}
```
✅ Correct:
```css
html {
background-color: var(--custom-tag-surface-default);
}
```
## aksel/design-token-no-global-override
Makes sure you don't override global level tokens with `--a-`-prefix. Global/Semantic tokens are supposed to be used as is, and not overridden. That is unless you are theming your solution to match a different sub-brands or brands. In those cases we encourage to make all the changes in a single 'config'-file, then disable the rule for that file only.
❌ Incorrect:
```css
div {
--a-surface-default: #f2f2f2;
^^^^^^^^^^^^^^^^^^^
}
```
✅ Correct:
```css
div {
background-color: var(--a-surface-default);
}
```
## aksel/design-token-no-component-reference
Makes sure you don't reference component level tokens with `--ac-`-prefix. Component level tokens are only supposed to be overridden, not referenced.
This is since they are by default not defined, leading to unknown side-effects when referenced incorrectly.
❌ Incorrect:
```css
html {
stroke: var(--ac-button-loader-stroke);
^^^^^^^^^^^^^^^^^^^^^^^^^
}
```
✅ Correct:
```css
html {
--ac-button-loader-stroke: lawngreen;
}
```
## aksel/no-internal-tokens
Disallows use or override of internal Aksel design tokens. Internal tokens are not supposed to be used outside the design system, and may be changed or removed without warning. Be aware that the rule simply checks the prefix of the token, and not if it actually exists in the design system. Even if it doesn't exist, using design system prefixes should be avoided.
❌ Incorrect:
```css
a {
--__ac-some-property: pink;
} ^^^^^^^^^^^^^^^^^^^^
```
```css
a {
color: var(--__ac-some-property);
} ^^^^^^^^^^^^^^^^^^^^
```
✅ Correct:
```css
a {
--some-property: pink;
}
```
```css
a {
color: var(--some-property);
}
```
## aksel/no-class-override
Warns when trying to override design system styling by using class selectors that starts with "navds-" or "navdsi-". Overriding styles in the design system is discouraged. We want to have consistent look and feel across applications. Even if it seems to work fine now, it might break on subsequent updates in the design system.
❌ Incorrect:
```css
.navds-button {
^^^^^^^^^^^^^
}
```
```css
.some-class .navdsi-header {
} ^^^^^^^^^^^^^^
```
✅ Correct:
```css
.some-class {
}
```
## aksel/no-deprecated-classes
Warns when you try to use deprecated class names.
❌ Incorrect:
```css
.navdsi-deprecated-example {
^^^^^^^^^^^^^^^^^^^^^^^^^^
}
```
✅ Correct:
```css
.guaranteed-not-deprecated {
}
```
🐛 Found a bug? https://github.com/navikt/aksel/issues
+59
View File
@@ -0,0 +1,59 @@
{
"name": "@navikt/aksel-stylelint",
"version": "4.1.3",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
"repository": {
"type": "git",
"url": "git+https://github.com/navikt/aksel.git",
"directory": "@navikt/aksel-stylelint"
},
"keywords": [
"aksel",
"stylelint",
"config",
"linting"
],
"publishConfig": {
"access": "public"
},
"license": "MIT",
"main": "./dist/index.js",
"exports": {
"./recommended": "./dist/recommended.js"
},
"files": [
"/dist"
],
"scripts": {
"test": "jest",
"copy-css": "node -e \"require('fs').copyFileSync('../core/css/dist/index.css','dist/index.css')\"",
"copy-tokens": "node -e \"require('fs').copyFileSync('../core/css/tokens.json','dist/tokens.json')\"",
"copy": "yarn copy-css && yarn copy-tokens",
"build": "tsc -p . && concurrently \"yarn:copy-*\"",
"watch:lint": "tsc --watch -p .",
"dev": "yarn watch:lint"
},
"devDependencies": {
"@navikt/ds-css": "^4.1.3",
"@navikt/ds-tokens": "^4.1.3",
"@types/jest": "^29.0.0",
"concurrently": "7.2.1",
"copyfiles": "2.4.1",
"jest": "^29.0.0",
"jest-preset-stylelint": "^6.1.0",
"postcss-selector-parser": "^6.0.13",
"postcss-value-parser": "^4.2.0",
"stylelint": "^14.8.5",
"typescript": "^4.8.0"
},
"jest": {
"preset": "jest-preset-stylelint",
"testMatch": [
"**/*.test.ts"
],
"transform": {
"^.+\\.ts?$": "ts-jest"
}
}
}
@@ -0,0 +1,28 @@
type DeprecatedList = {
classes: string[];
message: string;
deprecatePrefix?: boolean;
}[];
export const deprecations: DeprecatedList = [
{
classes: ["navdsi-deprecated-example", "navdsi-other-deprecated-example"],
message: "Removed in vX.X.X, see documentation [link] for more information",
},
{
classes: [
"navdsi-dropdown",
"navdsi-copy-to-clipboard",
"navdsi-header",
"navdsi-timeline",
],
message:
"Class were moved to '@navikt/ds-css' and renamed with 'navds'-prefix in v4.0.0. Docs: https://aksel.nav.no/grunnleggende/kode/endringslogg#h728704adeb59.",
deprecatePrefix: true,
},
{
classes: ["navds-chips--icon-left"],
message:
"In v4.1.0 Chips. Toggle no longer handles special alignment for checkmark-icon, thus removing this class",
},
];
+8
View File
@@ -0,0 +1,8 @@
import { createPlugin } from "stylelint";
import { rules } from "./rules";
const rulesPlugins = Object.keys(rules).map((ruleName) => {
return createPlugin(`${ruleName}`, rules[ruleName]);
});
export default rulesPlugins;
@@ -0,0 +1,11 @@
module.exports = {
plugins: ["."],
rules: {
"aksel/design-token-exists": true,
"aksel/no-internal-tokens": true,
"aksel/no-class-override": [true, { severity: "warning" }],
"aksel/no-deprecated-classes": true,
"aksel/design-token-no-global-override": true,
"aksel/design-token-no-component-reference": true,
},
};
@@ -0,0 +1,94 @@
import { getTestRule } from "jest-preset-stylelint";
import rule, { messages } from ".";
getTestRule()({
plugins: ["./dist/index.js"],
ruleName: rule.ruleName,
config: true,
accept: [
{
code: ".foo { --ac-accordion-header-bg-hover: 1px; --ac-internalheader-bg: red; }",
description: "existing '--ac-' tokens overridden",
},
{
code: ".foo { --my-custom-color: var(--a-orange-800); }",
description: "existing '--a-' token referenced",
},
],
reject: [
{
code: ".foo { --a-does-not-exist: 1px }",
description: "attempt to override nonexistent '--a-' token",
warnings: [
{
message: messages.propNotExist({ prop: "--a-does-not-exist" }),
line: 1,
endLine: 1,
column: 8,
endColumn: 26,
},
],
},
{
code: ".foo \n { \n --ac-does-not-exist: 1px; \n }",
description: "attempt to override nonexistent '--ac-' token",
message: messages.propNotExist({ prop: "--ac-does-not-exist" }),
line: 3,
endLine: 3,
column: 2,
endColumn: 21,
},
{
code: ".foo { color: var(--a-bar) }",
description: "attempt to use nonexistent token",
message: messages.valueNotExist({ prop: "color" }, "--a-bar"),
line: 1,
endLine: 1,
column: 19,
endColumn: 26,
},
{
code: ".foo { width: var(--ac-bar, --a-baz) }",
description: "attempt to use two nonexistent tokens in one var()",
warnings: [
{
message: messages.valueNotExist({ prop: "width" }, "--ac-bar"),
line: 1,
endLine: 1,
column: 19,
endColumn: 27,
},
{
message: messages.valueNotExist({ prop: "width" }, "--a-baz"),
line: 1,
endLine: 1,
column: 29,
endColumn: 36,
},
],
},
{
code: ".foo { padding: var(--a-bar) var(--a-baz); }",
description: "attempt to use two nonexistent tokens as separate vars",
warnings: [
{
message: messages.valueNotExist({ prop: "padding" }, "--a-bar"),
line: 1,
endLine: 1,
column: 21,
endColumn: 28,
},
{
message: messages.valueNotExist({ prop: "padding" }, "--a-baz"),
line: 1,
endLine: 1,
column: 34,
endColumn: 41,
},
],
},
],
});
@@ -0,0 +1,96 @@
import stylelint from "stylelint";
import valueParser from "postcss-value-parser";
import { readFileSync } from "node:fs";
import { Node as PostCSSNode } from "postcss";
import { isCustomProperty, tokenExists } from "../../utils";
const packageJson = JSON.parse(
readFileSync(`${__dirname}/../../../package.json`).toString()
);
const ruleName = "aksel/design-token-exists";
const prefix_a = "--a-";
const prefix_ac = "--ac-";
export const controlledPrefixes = [prefix_a, prefix_ac];
const packageVersion = packageJson.version;
export const messages = stylelint.utils.ruleMessages(ruleName, {
propNotExist: (node: any) =>
`("${node.prop}") does not exist in the design system.\n\n` +
`Property "${node.prop}" has a name that seems like it intends to override a design token by ` +
`using one of the following prefixes [${controlledPrefixes}]. ` +
`However, that token doesn"t seem to exist in the design system. ` +
`\n\nVersion: ${packageVersion}`,
valueNotExist: (node: any, invalidValues: string) =>
`("${invalidValues}") does not exist in the design system.\n\n` +
`Property "${node.prop}" has offending value "${invalidValues}", ` +
`and the value seems like it intends to reference a design token by ` +
`using one of the following prefixes [${controlledPrefixes}]. ` +
`However, that token doesn't seem to exist in the design system. ` +
`\n\nVersion: ${packageVersion}`,
});
const checkDeclValue = (
controlledPrefixes: string[],
value: string,
postcssResult: stylelint.PostcssResult,
rootNode: PostCSSNode
) => {
valueParser(value).walk((node) => {
if (
node.type === "word" &&
isCustomProperty(node.value) &&
controlledPrefixes.some((prefix) => node.value.startsWith(prefix)) &&
!tokenExists(controlledPrefixes, node.value)
) {
stylelint.utils.report({
message: messages.valueNotExist(rootNode, node.value),
node: rootNode,
result: postcssResult,
ruleName,
word: node.value,
});
}
});
};
const checkDeclProp = (
controlledPrefixes: string[],
prop: string,
postcssResult: stylelint.PostcssResult,
rootNode: PostCSSNode
) => {
if (
isCustomProperty(prop) &&
controlledPrefixes.some((prefix) => prop.startsWith(prefix)) &&
!tokenExists(controlledPrefixes, prop)
) {
stylelint.utils.report({
message: messages.propNotExist(rootNode),
node: rootNode,
result: postcssResult,
ruleName,
word: prop,
});
}
};
const ruleFunction: stylelint.Rule = () => {
return (postcssRoot, postcssResult) => {
postcssRoot.walkDecls((node) => {
checkDeclValue(controlledPrefixes, node.value, postcssResult, node);
checkDeclProp(controlledPrefixes, node.prop, postcssResult, node);
});
};
};
ruleFunction.ruleName = ruleName;
ruleFunction.messages = {};
ruleFunction.meta = {
url: `https://github.com/navikt/aksel/blob/main/%40navikt/aksel-stylelint/README.md#${ruleName}`,
};
export default ruleFunction;
@@ -0,0 +1,34 @@
import { getTestRule } from "jest-preset-stylelint";
import rule, { messages } from ".";
getTestRule()({
plugins: ["./dist/index.js"],
ruleName: rule.ruleName,
config: true,
accept: [
{
code: ".foo { --ac-accordion-header-bg-hover: 1px; --ac-header-bg: red; }",
description: "existing '--ac-' tokens overridden",
},
{
code: ".foo { --my-custom-color: var(--a-orange-800); }",
description: "existing '--a-' token referenced",
},
],
reject: [
{
code: ".foo { width: var(--ac-button-padding) }",
description: "attempt to use '--ac-' token",
message: messages.valueRefComponent(
{ prop: "width" },
"--ac-button-padding"
),
line: 1,
endLine: 1,
column: 19,
endColumn: 38,
},
],
});
@@ -0,0 +1,60 @@
import stylelint from "stylelint";
import { Node as PostCSSNode } from "postcss";
import valueParser from "postcss-value-parser";
import { getPackageVersion, isCustomProperty, tokenExists } from "../../utils";
const ruleName = "aksel/design-token-no-component-reference";
const packageVersion = getPackageVersion();
const prefix_ac = "--ac-";
export const messages = stylelint.utils.ruleMessages(ruleName, {
valueRefComponent: (node: any, invalidValue: string) =>
`Referencing ("${prefix_ac}*") not allowed.\n\n` +
`Property "${node.prop}" has offending value "${invalidValue}". ` +
`The value references a component level token ("${prefix_ac}"). ` +
`It is better to either reference a global level token ("--a-") or ` +
`create a custom token instead. ` +
`\n\nVersion: ${packageVersion}`,
});
const checkDeclValue = (
controlledPrefixes: string[],
value: string,
postcssResult: stylelint.PostcssResult,
rootNode: PostCSSNode
) => {
valueParser(value).walk((node) => {
if (
node.type === "word" &&
isCustomProperty(node.value) &&
node.value.startsWith(prefix_ac) &&
tokenExists(controlledPrefixes, node.value)
) {
stylelint.utils.report({
message: messages.valueRefComponent(rootNode, node.value),
node: rootNode,
result: postcssResult,
ruleName,
word: node.value,
});
}
});
};
const ruleFunction: stylelint.Rule = () => {
return (postcssRoot, postcssResult) => {
postcssRoot.walkDecls((node) => {
checkDeclValue([prefix_ac], node.value, postcssResult, node);
});
};
};
ruleFunction.ruleName = ruleName;
ruleFunction.messages = {};
ruleFunction.meta = {
url: `https://github.com/navikt/aksel/blob/main/%40navikt/aksel-stylelint/README.md#${ruleName}`,
};
export default ruleFunction;
@@ -0,0 +1,44 @@
import { getTestRule } from "jest-preset-stylelint";
import rule, { messages } from ".";
getTestRule()({
plugins: ["./dist/index.js"],
ruleName: rule.ruleName,
config: true,
accept: [
{
code: ".foo { --ac-accordion-header-bg-hover: 1px; --ac-header-bg: red; }",
description: "existing '--ac-' tokens overridden",
},
{
code: ".foo { --my-custom-color: var(--a-orange-800); }",
description: "existing '--a-' token referenced",
},
],
reject: [
{
code: ".foo { --a-surface-action: 1px }",
description: "existing '--a-' token overridden",
message: messages.propOverrideGlobal({ prop: "--a-surface-action" }),
line: 1,
endLine: 1,
column: 8,
endColumn: 26,
},
{
code: ".foo { --a-does-not-exist: 1px }",
description: "attempt to override nonexistent '--a-' token",
warnings: [
{
message: messages.propOverrideGlobal({ prop: "--a-does-not-exist" }),
line: 1,
endLine: 1,
column: 8,
endColumn: 26,
},
],
},
],
});
@@ -0,0 +1,62 @@
import stylelint from "stylelint";
import { readFileSync } from "node:fs";
import { Node as PostCSSNode } from "postcss";
import { isCustomProperty } from "../../utils";
const packageJson = JSON.parse(
readFileSync(`${__dirname}/../../../package.json`).toString()
);
const ruleName = "aksel/design-token-no-global-override";
const prefix_a = "--a-";
const packageVersion = packageJson.version;
export const messages = stylelint.utils.ruleMessages(ruleName, {
propOverrideGlobal: (node: any) =>
`Overriding ("${node.prop}*") not allowed.\n\n` +
`Property "${node.prop}" tries to override a global level token ("${prefix_a}"), this is highly discouraged. ` +
`It is better to override a component level token ("--ac-") or create a custom token instead. ` +
`Overriding global tokens should only be done when creating custom global themes.` +
`\n\nVersion: ${packageVersion}`,
});
const checkDeclProp = (
controlledPrefixes: string[],
prop: string,
postcssResult: stylelint.PostcssResult,
rootNode: PostCSSNode
) => {
if (
isCustomProperty(prop) &&
controlledPrefixes.some((prefix) => prop.startsWith(prefix))
) {
if (prop.startsWith(prefix_a)) {
stylelint.utils.report({
message: messages.propOverrideGlobal(rootNode),
node: rootNode,
result: postcssResult,
ruleName,
word: prop,
});
}
}
};
const ruleFunction: stylelint.Rule = () => {
return (postcssRoot, postcssResult) => {
postcssRoot.walkDecls((node) => {
checkDeclProp([prefix_a], node.prop, postcssResult, node);
});
};
};
ruleFunction.ruleName = ruleName;
ruleFunction.messages = {};
ruleFunction.meta = {
url: `https://github.com/navikt/aksel/blob/main/%40navikt/aksel-stylelint/README.md#${ruleName}`,
};
export default ruleFunction;
@@ -0,0 +1,31 @@
import { getTestRule } from "jest-preset-stylelint";
import rule, { messages } from ".";
getTestRule()({
plugins: ["./dist/index.js"],
ruleName: rule.ruleName,
config: true,
accept: [{ code: ".foo-navds-bar {}", description: "allowed class name" }],
reject: [
{
code: ".foo, \n .navds-button \n .bar {}",
description: "selector with disallowed class name .navds-*",
message: messages.unexpected("navds-button"),
line: 2,
endLine: 2,
column: 3,
endColumn: 15,
},
{
code: ".foo .navdsi-button \n .bar {}",
description: "selector with disallowed class name .navdsi-*",
message: messages.unexpected("navdsi-button"),
line: 1,
endLine: 1,
column: 7,
endColumn: 20,
},
],
});
@@ -0,0 +1,42 @@
import stylelint from "stylelint";
import selectorParser from "postcss-selector-parser";
const ruleName = "aksel/no-class-override";
const url =
"https://github.com/navikt/aksel/blob/main/%40navikt/aksel-stylelint/README.md#aksel/no-class-override";
const prefixes = ["navds-", "navdsi-"];
export const messages = stylelint.utils.ruleMessages(ruleName, {
unexpected: (value) =>
`("${value}") not allowed.\n\n` +
`"${value}" looks like a class name used in the design system, ` +
`because it starts with "${prefixes.join('" or "')}". ` +
"It is not recommended to override the styling in the design system.",
});
const ruleFunction: stylelint.Rule = () => {
return (postcssRoot, postcssResult) => {
postcssRoot.walkRules((node) => {
selectorParser((selectors) => {
selectors.walkClasses((className) => {
if (!prefixes.some((prefix) => className.value.startsWith(prefix))) {
return;
}
stylelint.utils.report({
message: messages.unexpected(className.value),
node,
result: postcssResult,
ruleName,
word: className.value,
});
});
}).processSync(node.selector);
});
};
};
ruleFunction.ruleName = ruleName;
ruleFunction.messages = messages;
ruleFunction.meta = { url };
export default ruleFunction;
@@ -0,0 +1,56 @@
import { getTestRule } from "jest-preset-stylelint";
import rule, { messages } from ".";
import { deprecations } from "../../deprecations";
getTestRule()({
plugins: ["./dist/index.js"],
ruleName: rule.ruleName,
config: true,
accept: [
{
code: ".navds-foo, navdsi-bar, .baz {}",
description: "allowed class names",
// Allowed because this rule only checks deprecated class names. See also aksel/no-class-override.
},
],
reject: [
{
code: ".foo, \n .navdsi-deprecated-example \n .bar {}",
description: "selector with deprecated class name 1",
message: messages.unexpected(
"navdsi-deprecated-example",
deprecations[0].message
),
line: 2,
endLine: 2,
column: 3,
endColumn: 28,
},
{
code: ".foo .navdsi-other-deprecated-example \n .bar {}",
description: "selector with deprecated class name 2",
message: messages.unexpected(
"navdsi-other-deprecated-example",
deprecations[0].message
),
line: 1,
endLine: 1,
column: 7,
endColumn: 38,
},
{
code: ".foo, \n .navdsi-dropdown-example \n .bar {}",
description: "selector with deprecated class name 1",
message: messages.unexpected(
"navdsi-dropdown-example",
deprecations[1].message
),
line: 2,
endLine: 2,
column: 3,
endColumn: 26,
},
],
});
@@ -0,0 +1,52 @@
import stylelint from "stylelint";
import selectorParser from "postcss-selector-parser";
import { deprecations } from "../../deprecations";
const ruleName = "aksel/no-deprecated-classes";
const url =
"https://github.com/navikt/aksel/blob/main/%40navikt/aksel-stylelint/README.md#aksel/no-deprecated-classes";
export const messages = stylelint.utils.ruleMessages(ruleName, {
unexpected: (value, secondaryOption) =>
`Class "${value}" is deprecated. ` + secondaryOption,
});
const ruleFunction: stylelint.Rule = () => {
return (postcssRoot, postcssResult) => {
postcssRoot.walkRules((node) => {
selectorParser((selectors) => {
selectors.walkClasses((className) => {
for (const deprecation of deprecations) {
if (
!deprecation.deprecatePrefix &&
!deprecation.classes.includes(className.value)
) {
continue;
} else if (
deprecation.deprecatePrefix &&
!deprecation.classes.some((x) => className.value.startsWith(x))
) {
return;
}
stylelint.utils.report({
message: messages.unexpected(
className.value,
deprecation.message
),
node,
result: postcssResult,
ruleName,
word: className.value,
});
}
});
}).processSync(node.selector);
});
};
};
ruleFunction.ruleName = ruleName;
ruleFunction.messages = messages;
ruleFunction.meta = { url };
export default ruleFunction;
@@ -0,0 +1,80 @@
import { getTestRule } from "jest-preset-stylelint";
import rule, { messages } from ".";
getTestRule()({
plugins: ["./dist/index.js"],
ruleName: rule.ruleName,
config: true,
accept: [
{
code: ".foo { --bar--__ac-baz: 1px }",
description: "non-internal token defined",
},
{
code: ".foo { font-size: var(--bar--__ac-baz) }",
description: "non-internal token used",
},
],
reject: [
{
code: ".foo { --__ac-bar: 1px; }",
description: "internal token overridden",
message: messages.tokenOverridden("--__ac-bar"),
line: 1,
endLine: 1,
column: 8,
endColumn: 24,
},
{
code: ".foo { color: var(--__ac-bar) }",
description: "one internal token used",
message: messages.tokenUsed("--__ac-bar", "color"),
line: 1,
endLine: 1,
column: 19,
endColumn: 29,
},
{
code: ".foo { width: var(--__ac-bar, --__ac-baz) }",
description: "two internal tokens used in one var()",
warnings: [
{
message: messages.tokenUsed("--__ac-bar", "width"),
line: 1,
endLine: 1,
column: 19,
endColumn: 29,
},
{
message: messages.tokenUsed("--__ac-baz", "width"),
line: 1,
endLine: 1,
column: 31,
endColumn: 41,
},
],
},
{
code: ".foo { padding: var(--__ac-bar) var(--__ac-baz); }",
description: "two internal tokens used as separate vars",
warnings: [
{
message: messages.tokenUsed("--__ac-bar", "padding"),
line: 1,
endLine: 1,
column: 21,
endColumn: 31,
},
{
message: messages.tokenUsed("--__ac-baz", "padding"),
line: 1,
endLine: 1,
column: 37,
endColumn: 47,
},
],
},
],
});
@@ -0,0 +1,62 @@
import stylelint from "stylelint";
import valueParser from "postcss-value-parser";
const ruleName = "aksel/no-internal-tokens";
const url =
"https://github.com/navikt/aksel/blob/main/%40navikt/aksel-stylelint/README.md#aksel/no-internal-tokens";
const prefix = "--__ac-";
export const messages = stylelint.utils.ruleMessages(ruleName, {
tokenUsed: (token, prop) =>
`("${token}") not allowed.\n\n` +
`"${token}" (inside decleration "${prop}") looks like an internal design token, ` +
`because it starts with "${prefix}". Internal tokens should not be used outside the design system.`,
tokenOverridden: (token) =>
`("${token}") not allowed.\n\n` +
`"${token}" looks like an internal design token, because it starts with "${prefix}". ` +
`Internal tokens should not be overridden.`,
});
const getInternalTokensUsed = (value: string) => {
const invalidValues: string[] = [];
valueParser(value).walk((node) => {
if (node.type === "word" && node.value.startsWith(prefix)) {
invalidValues.push(node.value);
}
});
return invalidValues;
};
const ruleFunction: stylelint.Rule = () => {
return (postcssRoot, postcssResult) => {
postcssRoot.walkDecls((node) => {
getInternalTokensUsed(node.value).forEach((token) => {
stylelint.utils.report({
message: messages.tokenUsed(token, node.prop),
node,
result: postcssResult,
ruleName,
word: token,
});
});
const isTokenOverride = node.prop.startsWith(prefix);
if (isTokenOverride) {
stylelint.utils.report({
message: messages.tokenOverridden(node.prop),
node,
result: postcssResult,
ruleName,
});
}
});
};
};
ruleFunction.ruleName = ruleName;
ruleFunction.messages = {};
ruleFunction.meta = { url };
export default ruleFunction;
@@ -0,0 +1,16 @@
import { Rule } from "stylelint";
import designTokenExists from "./aksel-design-token-exists";
import internalTokens from "./aksel-no-internal-tokens";
import classOverride from "./aksel-no-class-override";
import deprecatedClasses from "./aksel-no-deprecated-classes";
import noGlobalOverride from "./aksel-design-token-no-global-override";
import noComponentReference from "./aksel-design-token-no-component-reference";
export const rules: Record<string, Rule> = {
"aksel/design-token-exists": designTokenExists,
"aksel/design-token-no-global-override": noGlobalOverride,
"aksel/design-token-no-component-reference": noComponentReference,
"aksel/no-internal-tokens": internalTokens,
"aksel/no-class-override": classOverride,
"aksel/no-deprecated-classes": deprecatedClasses,
};
+136
View File
@@ -0,0 +1,136 @@
import { readFileSync } from "node:fs";
import valueParser from "postcss-value-parser";
export const isCustomProperty = (property) => {
return property.startsWith("--");
};
export const matchesStringOrRegExp = (input, comparison) => {
if (!Array.isArray(input)) {
return testAgainstStringOrRegExpOrArray(input, comparison);
}
for (const inputItem of input) {
const testResult = testAgainstStringOrRegExpOrArray(inputItem, comparison);
if (testResult) {
return testResult;
}
}
return false;
};
export const testAgainstStringOrRegExpOrArray = (value, comparison) => {
if (!Array.isArray(comparison)) {
return testAgainstStringOrRegExp(value, comparison);
}
for (const comparisonItem of comparison) {
const testResult = testAgainstStringOrRegExp(value, comparisonItem);
if (testResult) {
return testResult;
}
}
return false;
};
export const testAgainstStringOrRegExp = (value, comparison) => {
// If it's a RegExp, test directly
if (comparison instanceof RegExp) {
return comparison.test(value)
? { match: value, pattern: comparison }
: false;
}
// Check if it's RegExp in a string
const firstComparisonChar = comparison[0];
const lastComparisonChar = comparison[comparison.length - 1];
const secondToLastComparisonChar = comparison[comparison.length - 2];
const comparisonIsRegex =
firstComparisonChar === "/" &&
(lastComparisonChar === "/" ||
(secondToLastComparisonChar === "/" && lastComparisonChar === "i"));
const hasCaseInsensitiveFlag =
comparisonIsRegex && lastComparisonChar === "i";
// If so, create a new RegExp from it
if (comparisonIsRegex) {
const valueMatches = hasCaseInsensitiveFlag
? new RegExp(comparison.slice(1, -2), "i").test(value)
: new RegExp(comparison.slice(1, -1)).test(value);
return valueMatches ? { match: value, pattern: comparison } : false;
}
// Otherwise, it's a string. Do a strict comparison
return value === comparison ? { match: value, pattern: comparison } : false;
};
export const vendorUnprefixed = (prop) => {
return prop.replace(/^-\w+-/, "");
};
export const flattenObject = (obj) => {
const flattened = Object.keys(obj).reduce((acc, key) => {
if (typeof obj[key] === "string") {
acc.push(key);
} else {
acc.push(flattenObject(obj[key]));
}
return acc;
}, []);
return flattened.flat();
};
const tokenCSSFile = "./index.css";
const tokenJsonFile = "./tokens.json";
let allowedTokenNames = [];
export const addTokens = (
tokenJSONFile: string,
allowedTokenNames: string[]
) => {
const jsonFileBuffer = readFileSync(`${__dirname}/${tokenJSONFile}`);
const fileString = jsonFileBuffer.toString();
const flattened = flattenObject(JSON.parse(fileString));
flattened.forEach((token) => allowedTokenNames.push(token));
};
export const tokenExists = (
controlledPrefixes: string[],
inputToken: string
) => {
// "singleton" if statement (attempt at caching file parsing)
if (!allowedTokenNames.length) {
const cssFileBuffer = readFileSync(`${__dirname}/${tokenCSSFile}`);
const cssFileString = cssFileBuffer.toString();
valueParser(cssFileString).walk((node) => {
if (
node.type === "word" &&
isCustomProperty(node.value) &&
controlledPrefixes.some((prefix) => node.value.startsWith(prefix))
) {
allowedTokenNames.push(node.value);
}
});
addTokens(tokenJsonFile, allowedTokenNames);
}
return allowedTokenNames.includes(inputToken);
};
const packageJson = JSON.parse(
readFileSync(`${__dirname}/../package.json`).toString()
);
export const getPackageVersion = () => {
return packageJson.version;
};
+18
View File
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"module": "CommonJS",
"sourceMap": false,
"esModuleInterop": true,
"target": "es2020",
"preserveWatchOutput": true,
"declaration": false,
"types": ["node", "jest", "@types/jest"],
"outDir": "dist",
"rootDir": "./src",
"resolveJsonModule": true,
"allowJs": true,
"skipLibCheck": true
},
"include": ["**/*.ts"],
"exclude": ["node_modules", "dist", "**/tests/**"]
}
+105
View File
@@ -1,5 +1,110 @@
# @navikt/aksel
## 4.1.3
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@4.1.3
## 4.1.2
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@4.1.2
## 4.1.1
### Patch Changes
- Updated dependencies [[`91343563c`](https://github.com/navikt/aksel/commit/91343563c916a554d8ade5401c28ab4c3b3e26af)]:
- @navikt/ds-css@4.1.1
## 4.1.0
### Patch Changes
- Updated dependencies [[`7b42f536a`](https://github.com/navikt/aksel/commit/7b42f536aa90c1b5dbe2b19f1bbe292701546420), [`c028f36e2`](https://github.com/navikt/aksel/commit/c028f36e2bc58223ebf8b655980dde7eafb30add), [`b2f796d68`](https://github.com/navikt/aksel/commit/b2f796d681f1c1d76d26d1fd743268c8c618a854), [`db8c38a09`](https://github.com/navikt/aksel/commit/db8c38a094cd183db54aebecb62d5b223920a040)]:
- @navikt/ds-css@4.1.0
## 4.0.0
### Major Changes
- [#2026](https://github.com/navikt/aksel/pull/2026) [`895bdc08e`](https://github.com/navikt/aksel/commit/895bdc08e50647d9b9186cbf0e9ab069323de56c) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :test-tube: Datepicker og Monthpicker er nå ute av beta. Kjør codemod for migrering, eller `cmd/ctrl + shift + f` og erstatt `UNSAFE_` med ``
- UNSAFE-prefix er fjernet fra Datepicker og Monthpicker
```bash
npx @navikt/aksel codemod v4-date
```
- [#2026](https://github.com/navikt/aksel/pull/2026) [`895bdc08e`](https://github.com/navikt/aksel/commit/895bdc08e50647d9b9186cbf0e9ab069323de56c) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :truck: Komponenter i `@navikt/ds-react-internal` er flyttet over til `@navikt/ds-react`
- `<Header />` er renamet til `<InternalHeader />`
- Dropdown, Timeline og InternalHeader(Header) er flyttet over til `@navikt/ds-react`
- All styling fra `@navikt/ds-css-internal` er flyttet til `@navikt/ds-css` og classname-prefix er endret fra `navdsi` -> `navds` for flyttede komponenter. Sett opp [stylelint med configen vår](https://aksel.nav.no/grunnleggende/kode/stylelint), så vil du få feilmelding om du bruker gamle klassenavn.
- Fikset cascading-problem mellom dropdown og popover. Dropdown blir ikke lengre påvirket av import-rekkefølge av popover.
- Styling for flyttede komponenter finnes nå på CDN (https://aksel.nav.no/grunnleggende/kode/css-import)
Kjør codemod for migrering:
```bash
// React
npx @navikt/aksel codemod v4-internal-react
// CSS
npx @navikt/aksel codemod v4-internal-css
```
### Patch Changes
- Updated dependencies [[`895bdc08e`](https://github.com/navikt/aksel/commit/895bdc08e50647d9b9186cbf0e9ab069323de56c), [`895bdc08e`](https://github.com/navikt/aksel/commit/895bdc08e50647d9b9186cbf0e9ab069323de56c)]:
- @navikt/ds-css@4.0.0
## 3.4.2
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@3.4.2
## 3.4.1
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@3.4.1
## 3.4.0
### Patch Changes
- Updated dependencies [[`b958d41a2`](https://github.com/navikt/aksel/commit/b958d41a20c66327658514fcf24ae20893c9531a)]:
- @navikt/ds-css@3.4.0
## 3.3.1
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@3.3.1
## 3.3.0
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@3.3.0
## 3.2.4
### Patch Changes
- Updated dependencies [[`30eee0dac`](https://github.com/navikt/aksel/commit/30eee0dac4e3e5a1379033283a6885e646e80458)]:
- @navikt/ds-css@3.2.4
## 3.2.3
### Patch Changes
+39
View File
@@ -22,6 +22,45 @@ To get started:
npx @navikt/aksel codemod --help
```
### v4
In v4, we moved all the components from `@navikt/ds-react-internal` to `@navikt/ds-react`. This means that you will need to update all your imports to the new package. As a part of this, Header was renamed to `InternalHeader` and all the CSS-classes was renamed to use `navds` as a prefix instead of `navdsi`.
#### react
`npx @navikt/aksel codemod v4-internal-react ...`
Rewrites all imports from `@navikt/ds-react-internal` to `@navikt/ds-react`. Remember to remove `@navikt/ds-react-internal` as a dependency after migration.
```diff
- import { Dropdown, Timeline, Header } from "@navikt/ds-react-internal";
- import { Button, CopyButton } from "@navikt/ds-react";
+ import { Button, CopyButton, Dropdown, Timeline, InternalHeader as Header } from "@navikt/ds-react";
```
#### css
`npx @navikt/aksel codemod v4-internal-css ...`
Rewrites all css with `navdsi`-prefix to `navds`-prefix. Rewrites all `.navdsi-header` classes to `.navds-internalheader`.
Remember to remove `@navikt/ds-css-internal` as a dependency after migration + remove it from you lists of imports in the CSS-bundle.
```diff
- .navdsi-dropdown
+ .navds-dropdown
- .navdsi-header
+ .navds-internalheader
- .navdsi-timeline
+ .navds-timeline
```
Note: This is a "dumb" codemod that uses a simple regex to find and replace. This can lead to unknown sideeffects, so its reccomended to scope the codemod to spesific files.
```bash
`npx @navikt/aksel codemod v4-internal-css **/*.css`
```
### v3
There is no general codemods for migrating from v2 -> v3.
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel",
"version": "3.2.3",
"version": "4.1.3",
"description": "Aksel command line interface. Handles css-imports, codemods and more",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -29,7 +29,7 @@
},
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
"dependencies": {
"@navikt/ds-css": "3.2.3",
"@navikt/ds-css": "4.1.3",
"axios": "1.3.6",
"chalk": "4.1.0",
"clipboardy": "^2.3.0",
+24
View File
@@ -63,6 +63,30 @@ export const migrations: {
"Remember to clean css-import from '@navikt/ds-css-internal' if no longer needed\nIf non-text was used as children, or different locales were handled, you need to manually fix this",
},
],
"v4.0.0": [
{
description:
"Replaced deprecated 'internal'-component import to 'core'-imports",
value: "v4-internal-react",
path: "v4.0.0/internal-react/internal-react",
warning:
"Remember to also run 'v4-internal-css' if you have overwritten any css-classes!",
},
{
description:
"Replaced 'navdsi'-prefixes used to overwrite internal-css to 'navds'-prefixes",
value: "v4-internal-css",
path: "v4.0.0/internal-css/internal-css",
warning:
"Remember to remove '@navikt/ds-css-internal' imports if no longer needed! Also run 'v4-internal-react' to convert internal-react imports to core-imports",
},
{
description:
"Removes all instances of UNSAFE_ for datepicker/monthpicker.",
value: "v4-date",
path: "v4.0.0/date/date",
},
],
};
export function getMigrationPath(str: string) {
@@ -1,3 +1,4 @@
import { getLineTerminator } from "../../../utils/lineterminator";
import renameProps from "../../../utils/rename-props";
/**
@@ -64,5 +65,5 @@ export default function transformer(file, api, options) {
});
}
return root.toSource(options.printOptions);
return root.toSource(getLineTerminator(file.source));
}
@@ -1,3 +1,5 @@
import { getLineTerminator } from "../../../utils/lineterminator";
/**
* @param {import('jscodeshift').FileInfo} file
* @param {import('jscodeshift').API} api
@@ -79,5 +81,5 @@ export default function transformer(file, api, options) {
});
}
return root.toSource(options.printOptions);
return root.toSource(getLineTerminator(file.source));
}
@@ -1,3 +1,4 @@
import { getLineTerminator } from "../../../utils/lineterminator";
import renameProps from "../../../utils/rename-props";
/**
@@ -79,5 +80,5 @@ export default function transformer(file, api, options) {
});
}
return root.toSource(options.printOptions);
return root.toSource(getLineTerminator(file.source));
}
@@ -6,6 +6,7 @@ import {
} from "../../../utils/imports";
import { translateToken } from "../../../utils/translate-token";
import { tokens } from "../../../tokens-map.mjs";
import { getLineTerminator } from "../../../utils/lineterminator";
/**
* @param {import('jscodeshift').FileInfo} file
@@ -55,7 +56,7 @@ export default function transformer(file: JSCodeshift, api) {
"@navikt/ds-tokens/dist/tokens"
);
let code = root.toSource();
let code = root.toSource(getLineTerminator(file.source));
const rgx = new RegExp("(" + localName + ")", "gm");
code = code.replace(rgx, out);
@@ -63,5 +64,5 @@ export default function transformer(file: JSCodeshift, api) {
}
});
return root.toSource();
return root.toSource(getLineTerminator(file.source));
}
@@ -1,6 +1,7 @@
import chalk from "chalk";
import moveAndRenameImport from "../../../utils/moveAndRenameImport";
import removePropsFromComponent from "../../../utils/removeProps";
import { getLineTerminator } from "../../../utils/lineterminator";
/**
* @param {import('jscodeshift').FileInfo} file
@@ -22,10 +23,11 @@ export default function transformer(file, api, options, ...rest) {
toImport: "@navikt/ds-react",
fromName: "CopyToClipboard",
toName,
ignoreAlias: true,
});
if (localName === null) {
return root.toSource(options.printOptions);
return root.toSource(getLineTerminator(file.source));
}
/* Finds and replaces import from CopyToClipboard -> CopyButton */
@@ -85,5 +87,5 @@ export default function transformer(file, api, options, ...rest) {
});
}
return root.toSource(options.printOptions);
return root.toSource(getLineTerminator(file.source));
}
@@ -0,0 +1,21 @@
/**
* @param {import('jscodeshift').FileInfo} file
* @param {import('jscodeshift').API} api
*/
export default function transformer(file) {
const names = [
"UNSAFE_useDatepicker",
"UNSAFE_DatePicker",
"UNSAFE_useRangeDatepicker",
"UNSAFE_MonthPicker",
"UNSAFE_useMonthpicker",
];
let src = file.source;
names.forEach((name) => {
src = src.replaceAll(name, name.replace("UNSAFE_", ""));
});
return src;
}
@@ -0,0 +1,72 @@
import {
UNSAFE_useDatepicker,
UNSAFE_DatePicker,
UNSAFE_useRangeDatepicker,
UNSAFE_MonthPicker,
UNSAFE_useMonthpicker as DsUnsafeUseMonthpicker,
} from "@navikt/ds-react";
/* eslint-disable react/jsx-no-undef */
export const UseDatepicker = () => {
const { datepickerProps, inputProps } = UNSAFE_useDatepicker({
fromDate: new Date("Aug 23 2019"),
toDate: new Date("Feb 23 2024"),
onDateChange: console.log,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<UNSAFE_DatePicker {...datepickerProps} dropdownCaption>
<UNSAFE_DatePicker.Input {...inputProps} label="Velg dato" />
</UNSAFE_DatePicker>
</div>
);
};
export const UseRangedDatepicker = () => {
const { datepickerProps, fromInputProps, toInputProps } =
UNSAFE_useRangeDatepicker({
fromDate: new Date("Aug 23 2019"),
onRangeChange: console.log,
onValidate: console.log,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<UNSAFE_DatePicker {...datepickerProps}>
<div style={{ display: "flex", gap: "1rem" }}>
<UNSAFE_DatePicker.Input {...fromInputProps} label="Fra" />
<UNSAFE_DatePicker.Input {...toInputProps} label="Til" />
</div>
</UNSAFE_DatePicker>
</div>
);
};
export const UseMonthpicker = () => {
const { inputProps, monthpickerProps } = UNSAFE_useMonthpicker({
disabled: [new Date("Apr 1 2022")],
onMonthChange: console.log,
fromDate: new Date("Jan 1 2022"),
toDate: new Date("Sep 27 2025"),
});
const {} = UNSAFE_useMonthpicker({
disabled: [new Date("Apr 1 2022")],
onMonthChange: console.log,
fromDate: new Date("Jan 1 2022"),
toDate: new Date("Sep 27 2025"),
});
return (
<div style={{ height: "20rem" }}>
<UNSAFE_MonthPicker {...monthpickerProps} dropdownCaption>
<UNSAFE_MonthPicker.Input
{...inputProps}
label="Velg måned"
variant="monthpicker"
/>
</UNSAFE_MonthPicker>
</div>
);
};
@@ -0,0 +1,71 @@
import {
useDatepicker,
DatePicker,
useRangeDatepicker,
MonthPicker,
useMonthpicker,
} from "@navikt/ds-react";
/* eslint-disable react/jsx-no-undef */
export const UseDatepicker = () => {
const { datepickerProps, inputProps } = useDatepicker({
fromDate: new Date("Aug 23 2019"),
toDate: new Date("Feb 23 2024"),
onDateChange: console.log,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker {...datepickerProps} dropdownCaption>
<DatePicker.Input {...inputProps} label="Velg dato" />
</DatePicker>
</div>
);
};
export const UseRangedDatepicker = () => {
const { datepickerProps, fromInputProps, toInputProps } = useRangeDatepicker({
fromDate: new Date("Aug 23 2019"),
onRangeChange: console.log,
onValidate: console.log,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker {...datepickerProps}>
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker.Input {...fromInputProps} label="Fra" />
<DatePicker.Input {...toInputProps} label="Til" />
</div>
</DatePicker>
</div>
);
};
export const UseMonthpicker = () => {
const { inputProps, monthpickerProps } = DsUnsafeUseMonthpicker({
disabled: [new Date("Apr 1 2022")],
onMonthChange: console.log,
fromDate: new Date("Jan 1 2022"),
toDate: new Date("Sep 27 2025"),
});
const {} = UNSAFE_useMonthpicker({
disabled: [new Date("Apr 1 2022")],
onMonthChange: console.log,
fromDate: new Date("Jan 1 2022"),
toDate: new Date("Sep 27 2025"),
});
return (
<div style={{ height: "20rem" }}>
<MonthPicker {...monthpickerProps} dropdownCaption>
<MonthPicker.Input
{...inputProps}
label="Velg måned"
variant="monthpicker"
/>
</MonthPicker>
</div>
);
};
@@ -1,12 +1,12 @@
import { check } from "../../../../utils/check";
const migration = "update-less-tokens";
const fixtures = ["complete"];
const migration = "date";
const fixtures = ["idempotent"];
for (const fixture of fixtures) {
check(__dirname, {
fixture,
migration,
extension: "less",
extension: "js",
});
}
@@ -0,0 +1,64 @@
import {
useDatepicker,
DatePicker,
useRangeDatepicker,
MonthPicker,
useMonthpicker,
} from "@navikt/ds-react";
/* eslint-disable react/jsx-no-undef */
export const UseDatepicker = () => {
const { datepickerProps, inputProps } = useDatepicker({
fromDate: new Date("Aug 23 2019"),
toDate: new Date("Feb 23 2024"),
onDateChange: console.log,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker {...datepickerProps} dropdownCaption>
<DatePicker.Input {...inputProps} label="Velg dato" />
</DatePicker>
</div>
);
};
export const UseRangedDatepicker = () => {
const { datepickerProps, fromInputProps, toInputProps } = useRangeDatepicker({
fromDate: new Date("Aug 23 2019"),
onRangeChange: console.log,
onValidate: console.log,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker {...datepickerProps}>
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker.Input {...fromInputProps} label="Fra" />
<DatePicker.Input {...toInputProps} label="Til" />
</div>
</DatePicker>
</div>
);
};
export const UseMonthpicker = () => {
const { inputProps, monthpickerProps } = useMonthpicker({
disabled: [new Date("Apr 1 2022")],
onMonthChange: console.log,
fromDate: new Date("Jan 1 2022"),
toDate: new Date("Sep 27 2025"),
});
return (
<div style={{ height: "20rem" }}>
<MonthPicker {...monthpickerProps} dropdownCaption>
<MonthPicker.Input
{...inputProps}
label="Velg måned"
variant="monthpicker"
/>
</MonthPicker>
</div>
);
};
@@ -0,0 +1,64 @@
import {
useDatepicker,
DatePicker,
useRangeDatepicker,
MonthPicker,
useMonthpicker,
} from "@navikt/ds-react";
/* eslint-disable react/jsx-no-undef */
export const UseDatepicker = () => {
const { datepickerProps, inputProps } = useDatepicker({
fromDate: new Date("Aug 23 2019"),
toDate: new Date("Feb 23 2024"),
onDateChange: console.log,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker {...datepickerProps} dropdownCaption>
<DatePicker.Input {...inputProps} label="Velg dato" />
</DatePicker>
</div>
);
};
export const UseRangedDatepicker = () => {
const { datepickerProps, fromInputProps, toInputProps } = useRangeDatepicker({
fromDate: new Date("Aug 23 2019"),
onRangeChange: console.log,
onValidate: console.log,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker {...datepickerProps}>
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker.Input {...fromInputProps} label="Fra" />
<DatePicker.Input {...toInputProps} label="Til" />
</div>
</DatePicker>
</div>
);
};
export const UseMonthpicker = () => {
const { inputProps, monthpickerProps } = useMonthpicker({
disabled: [new Date("Apr 1 2022")],
onMonthChange: console.log,
fromDate: new Date("Jan 1 2022"),
toDate: new Date("Sep 27 2025"),
});
return (
<div style={{ height: "20rem" }}>
<MonthPicker {...monthpickerProps} dropdownCaption>
<MonthPicker.Input
{...inputProps}
label="Velg måned"
variant="monthpicker"
/>
</MonthPicker>
</div>
);
};
@@ -0,0 +1,23 @@
const cssConversions = {
".navdsi-dropdown": ".navds-dropdown",
".navdsi-header": ".navds-internalheader",
".navdsi-timeline": ".navds-timeline",
"--ac-header-bg": "--ac-internalheader-bg",
"--ac-header-divider": "--ac-internalheader-divider",
"--ac-header-text": "--ac-internalheader-text",
"--ac-header-hover-bg": "--ac-internalheader-hover-bg",
"--ac-header-active-bg": "--ac-internalheader-active-bg",
};
/**
* @param {import('jscodeshift').FileInfo} file
* @param {import('jscodeshift').API} api
*/
export default function transformer(file) {
let src = file.source;
Object.entries(cssConversions).forEach(([key, value]) => {
src = src.replaceAll(key, value);
});
return src;
}
@@ -0,0 +1,545 @@
.navdsi-dropdown__menu {
overflow: hidden;
padding: var(--a-spacing-2) 0;
color: var(--ac-dropdown-text, var(--a-text-default));
width: 27ch;
max-height: 616px;
overflow-y: auto;
border-color: var(--ac-dropdown-border, var(--a-border-default));
}
.navdsi-dropdown__divider {
margin: var(--a-spacing-3) 0;
border: none;
border-bottom: 1px solid var(--a-border-divider);
}
.navdsi-dropdown__menu > :not(.navdsi-dropdown__divider):not(.navdsi-dropdown__list) {
margin: 0 var(--a-spacing-4) var(--a-spacing-3);
}
.navdsi-dropdown__list {
margin: 0;
padding: 0;
list-style: none;
}
.navdsi-dropdown__list-item {
margin: 0;
}
.navdsi-dropdown__list-heading {
margin: var(--a-spacing-1) var(--a-spacing-4) var(--a-spacing-3);
}
.navdsi-dropdown__item {
border: none;
margin: 0;
overflow: visible;
background: transparent;
color: var(--ac-dropdown-item-text, var(--a-text-action));
font: inherit;
text-decoration: none;
text-align: left;
cursor: pointer;
width: 100%;
display: flex;
align-items: center;
gap: var(--a-spacing-2);
padding: var(--a-spacing-1) var(--a-spacing-4);
}
.navdsi-dropdown__item:hover {
background-color: var(--ac-dropdown-item-hover-bg, var(--a-surface-action-subtle-hover));
}
.navdsi-dropdown__item:active {
background-color: var(--ac-dropdown-item-active-bg, var(--a-surface-action-active));
color: var(--ac-dropdown-item-active-text, var(--a-text-on-action));
}
.navdsi-dropdown__item:focus-visible {
outline: none;
box-shadow: inset 0 0 0 2px var(--a-border-focus);
}
@supports not selector(:focus-visible) {
.navdsi-dropdown__item:focus {
outline: none;
box-shadow: inset 0 0 0 2px var(--a-border-focus);
}
}
.navdsi-dropdown__item:disabled {
color: var(--ac-dropdown-item-text, var(--a-text-action));
opacity: 0.3;
background: transparent;
cursor: not-allowed;
}
.navdsi-header {
display: flex;
align-self: stretch;
background: var(--ac-header-bg, var(--a-surface-inverted));
min-height: var(--a-spacing-12);
--navdsi-header-focus: inset 0 0 0 2px var(--a-border-focus-on-inverted);
}
.navdsi-header__title {
border: none;
overflow: visible;
background: transparent;
font: inherit;
font-weight: var(--a-font-weight-bold);
line-height: normal;
text-align: left;
padding: 0 var(--a-spacing-5) 0 var(--a-spacing-6);
border-right: 1px solid var(--ac-header-divider, var(--a-gray-600));
display: flex;
align-items: center;
text-decoration: none;
margin: 0;
color: var(--ac-header-text, var(--a-text-on-inverted));
}
button.navdsi-header__title {
cursor: pointer;
}
.navdsi-header__user {
padding: 0 var(--a-spacing-5);
border-left: 1px solid var(--ac-header-divider, var(--a-gray-600));
display: flex;
align-items: center;
}
.navdsi-header__button {
border: none;
margin: 0;
padding: 0 var(--a-spacing-3);
overflow: visible;
background: transparent;
font: inherit;
line-height: normal;
cursor: pointer;
text-align: left;
display: flex;
align-items: center;
justify-self: center;
gap: var(--a-spacing-2);
border-left: 1px solid var(--ac-header-divider, var(--a-gray-600));
color: var(--ac-header-text, var(--a-text-on-inverted));
}
a.navdsi-header__title:hover,
button.navdsi-header__title:hover,
.navdsi-header__button:hover {
background-color: var(--ac-header-hover-bg, var(--a-surface-inverted-hover));
}
.navdsi-header__title:focus-visible,
.navdsi-header__button:focus-visible {
box-shadow: var(--navdsi-header-focus);
outline: none;
}
@supports not selector(:focus-visible) {
.navdsi-header__title:focus,
.navdsi-header__button:focus {
box-shadow: var(--navdsi-header-focus);
outline: none;
}
}
a.navdsi-header__title:active,
button.navdsi-header__title:active,
.navdsi-header__button:active {
background-color: var(--ac-header-active-bg, var(--a-surface-inverted-active));
}
.navdsi-header__user-button {
padding-left: var(--a-spacing-5);
gap: var(--a-spacing-4);
}
.navdsi-timeline {
position: relative;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
width: 100%;
min-width: fit-content;
align-items: center;
}
.navdsi-timeline__axislabels {
position: relative;
height: 1rem;
box-sizing: content-box;
grid-column: 2;
}
.navdsi-timeline__row-label {
white-space: nowrap;
width: auto;
margin-right: var(--a-spacing-4);
grid-column: 1;
min-height: 1.5rem;
display: flex;
align-items: center;
gap: var(--a-spacing-2);
}
.navdsi-timeline__row-label:where(:nth-last-child(2)) {
align-self: flex-end;
}
.navdsi-timeline__axislabels-label {
position: absolute;
color: var(--ac-timeline-axislabel-text, var(--a-text-subtle));
white-space: nowrap;
}
.navdsi-timeline__row {
display: flex;
background: var(--ac-timeline-row-bg, var(--a-surface-subtle));
margin: var(--a-spacing-4) 0;
grid-column: 2;
}
.navdsi-timeline__row--active {
background: var(--ac-timeline-row-active-bg, var(--a-surface-selected));
}
.navdsi-timeline__row:last-of-type {
margin-bottom: 0;
}
.navdsi-timeline__row-periods {
min-height: 1.5rem;
position: relative;
width: 100%;
margin: 0;
}
.navdsi-timeline__row-periods > li {
list-style-type: none;
}
.navdsi-timeline__period {
height: 100%;
border-radius: var(--a-border-radius-full);
position: absolute;
padding: 0;
display: flex;
align-items: center;
z-index: 2;
border: none;
font-size: 1rem;
}
.navdsi-timeline__period--inner {
margin: 0 var(--a-spacing-1);
overflow: hidden;
white-space: nowrap;
text-overflow: clip;
text-align: left;
display: flex;
align-items: center;
}
.navdsi-timeline__period--inner svg {
flex-shrink: 0;
}
.navdsi-timeline__period--clickable {
cursor: pointer;
}
.navdsi-timeline__period--success {
background: var(--ac-timeline-period-success-bg, var(--a-surface-success-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-success-border, var(--a-border-success));
}
.navdsi-timeline__period--success.navdsi-timeline__period--clickable:hover {
background: var(--a-surface-success-subtle-hover);
background: var(--ac-timeline-period-success-bg-hover, var(--a-surface-success-subtle-hover));
}
.navdsi-timeline__period--warning {
background: var(--ac-timeline-period-warning-bg, var(--a-surface-warning-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-warning-border, var(--a-border-warning));
}
.navdsi-timeline__period--warning.navdsi-timeline__period--clickable:hover {
background: var(--ac-timeline-period-warning-bg-hover, var(--a-surface-warning-subtle-hover));
}
.navdsi-timeline__period--danger {
background: var(--ac-timeline-period-danger-bg, var(--a-surface-danger-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-danger-border, var(--a-border-danger));
}
.navdsi-timeline__period--danger.navdsi-timeline__period--clickable:hover {
background: var(--ac-timeline-period-danger-bg-hover, var(--a-surface-danger-subtle-hover));
}
.navdsi-timeline__period--info {
background: var(--ac-timeline-period-info-bg, var(--a-surface-info-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-info-border, var(--a-border-info));
}
.navdsi-timeline__period--info.navdsi-timeline__period--clickable:hover {
background: var(--ac-timeline-period-info-bg-hover, var(--a-surface-info-subtle-hover));
}
.navdsi-timeline__period--neutral {
background: var(--ac-timeline-period-neutral-bg, var(--a-bg-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-neutral-border, var(--a-border-default));
}
.navdsi-timeline__period--neutral.navdsi-timeline__period--clickable:hover {
background: var(--ac-timeline-period-neutral-bg-hover, var(--a-gray-200));
}
.navdsi-timeline__period--connected-both {
border-radius: 0;
}
.navdsi-timeline__period--connected-right {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
.navdsi-timeline__period--connected-left {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
.navdsi-timeline__period--selected {
box-shadow: inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected));
z-index: 3;
}
.navdsi-timeline__pin-wrapper {
position: absolute;
grid-column: 2;
top: 0;
z-index: 1;
height: 100%;
display: flex;
flex-direction: column-reverse;
isolation: isolate;
--navdsc-timeline-pin-size: 0.9rem;
}
.navdsi-timeline__pin-button {
border: none;
cursor: pointer;
background: var(--a-surface-default);
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 4px var(--ac-timeline-pin-bg, var(--a-surface-danger)), 0 0 0 5px var(--a-surface-default);
z-index: 2;
border-radius: var(--a-border-radius-full);
padding: 3.5px;
position: relative;
}
.navdsi-timeline__pin-button::before {
content: "";
inset: 0;
position: absolute;
width: 25px;
height: 25px;
border-radius: var(--a-border-radius-full);
left: calc(-12.5px + 3.5px);
top: calc(-12.5px + 3.5px);
}
.navdsi-timeline__pin-button:focus-visible {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 3px var(--ac-timeline-pin-bg, var(--a-surface-danger)), 0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
outline: none;
}
.navdsi-timeline__pin-button:hover {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 4px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)), 0 0 0 5px var(--a-surface-default);
}
.navdsi-timeline__pin-button:hover:focus-visible {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 3px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)), 0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
}
@supports not selector(:focus-visible) {
.navdsi-timeline__pin-button:focus {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 3px var(--ac-timeline-pin-bg, var(--a-surface-danger)), 0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
outline: none;
}
.navdsi-timeline__pin-button:hover:focus {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 3px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)), 0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
}
}
.navdsi-timeline__pin-wrapper::before {
content: "";
top: var(--navdsc-timeline-pin-size);
height: calc(94% - var(--navdsc-timeline-pin-size));
width: 1px;
margin: 0 auto;
background: var(--a-surface-inverted);
}
.navdsi-timeline__zoom {
margin-top: var(--a-spacing-6);
float: right;
display: flex;
list-style-type: none;
}
.navdsi-timeline__zoom-button {
all: unset;
cursor: pointer;
padding: 6px 9px 6px 8px;
border: 1px solid var(--ac-timeline-zoom-border, var(--a-border-default));
border-width: 1px 0 1px 1px;
background: var(--ac-timeline-zoom-bg, var(--a-surface-default));
}
.navdsi-timeline__zoom li:first-child .navdsi-timeline__zoom-button {
border-radius: var(--a-border-radius-medium) 0 0 var(--a-border-radius-medium);
}
.navdsi-timeline__zoom li:last-child .navdsi-timeline__zoom-button {
border-width: 1px;
border-radius: 0 var(--a-border-radius-medium) var(--a-border-radius-medium) 0;
}
.navdsi-timeline__zoom li:only-child .navdsi-timeline__zoom-button {
border-radius: var(--a-border-radius-medium);
}
.navdsi-timeline__zoom-button:not([aria-pressed="true"]):hover {
background: var(--ac-timeline-zoom-bg-hover, var(--a-surface-action-subtle-hover));
}
.navdsi-timeline__zoom-button[aria-pressed="true"] {
background: var(--ac-timeline-zoom-selected-bg, var(--a-surface-inverted));
color: var(--ac-timeline-zoom-selected-text, var(--a-text-on-inverted));
}
.navdsi-timeline__period:focus-visible {
outline: none;
z-index: 4;
box-shadow: 0 0 0 2px var(--a-border-focus);
}
.navdsi-timeline__period--selected:focus-visible {
box-shadow: inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected)),
0 0 0 2px var(--a-border-focus);
z-index: 3;
}
.navdsi-timeline__zoom li:focus-within {
z-index: var(--a-z-index-focus);
}
.navdsi-timeline__zoom-button:focus-visible {
box-shadow: 0 0 0 1px var(--a-surface-default), 0 0 0 3px var(--a-border-focus);
border-width: 1px;
}
.navdsi-timeline__zoom li:not(:last-child) .navdsi-timeline__zoom-button:focus-visible {
margin-right: 2px;
padding-right: 6px;
}
@supports not selector(:focus-visible) {
.navdsi-timeline__period:focus {
outline: none;
z-index: 4;
box-shadow: 0 0 0 2px var(--a-border-focus);
}
.navdsi-timeline__period--selected:focus {
box-shadow: inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected)),
0 0 0 2px var(--a-border-focus);
z-index: 3;
}
.navdsi-timeline__zoom-button:focus {
box-shadow: 0 0 0 1px var(--a-surface-default), 0 0 0 3px var(--a-border-focus);
border-width: 1px;
}
.navdsi-timeline__zoom li:not(:last-child) .navdsi-timeline__zoom-button:focus {
margin-right: 2px;
padding-right: 6px;
}
}
/**
* Timeline Popover
*/
.navds-timeline__popover {
z-index: var(--a-z-index-popover);
background-color: var(--ac-popover-bg, var(--a-surface-default));
box-shadow: var(--a-shadow-medium);
border: 1px solid;
border-color: var(--ac-popover-border, var(--a-border-default));
border-radius: var(--a-border-radius-medium);
}
.navds-timeline__popover:focus {
outline: none;
}
.navds-timeline__popover-content {
padding: var(--a-spacing-3);
}
.navds-timeline__popover-arrow {
position: absolute;
z-index: -1;
transform: rotate(45deg);
background-color: var(--ac-popover-bg, var(--a-surface-default));
border: 1px solid;
border-color: var(--ac-popover-border, var(--a-border-default));
width: 1rem;
height: 1rem;
}
.navds-timeline__popover[data-placement^="top"] > .navds-timeline__popover-arrow {
border-left-color: transparent;
border-top-color: transparent;
}
.navds-timeline__popover[data-placement^="bottom"] > .navds-timeline__popover-arrow {
border-bottom-color: transparent;
border-right-color: transparent;
}
.navds-timeline__popover[data-placement^="left"] > .navds-timeline__popover-arrow {
border-left-color: transparent;
border-bottom-color: transparent;
}
.navds-timeline__popover[data-placement^="right"] > .navds-timeline__popover-arrow {
border-right-color: transparent;
border-top-color: transparent;
}
.tokens {
--ac-header-bg: red;
--ac-header-active-bg: orange;
}
@@ -0,0 +1,17 @@
const StyledDiv = styled`
.navdsi-dropdown__menu {}
.navdsi-dropdown__divider {}
button.navdsi-header__title:active {}
.navds-timeline__popover[data-placement^="left"] > .navds-timeline__popover-arrow {}
.navdsi-timeline__period--danger {}
`;
<style>
{`
.navdsi-dropdown__menu {}
.navdsi-dropdown__divider {}
button.navdsi-header__title:active {}
.navds-timeline__popover[data-placement^="left"] > .navds-timeline__popover-arrow {}
.navdsi-timeline__period--danger {}
`}
</style>;
@@ -0,0 +1,544 @@
.navds-dropdown__menu {
overflow: hidden;
padding: var(--a-spacing-2) 0;
color: var(--ac-dropdown-text, var(--a-text-default));
width: 27ch;
max-height: 616px;
overflow-y: auto;
}
.navds-dropdown__divider {
margin: var(--a-spacing-3) 0;
border: none;
border-bottom: 1px solid var(--a-border-divider);
}
.navds-dropdown__menu > :not(.navds-dropdown__divider):not(.navds-dropdown__list) {
margin: 0 var(--a-spacing-4) var(--a-spacing-3);
}
.navds-dropdown__list {
margin: 0;
padding: 0;
list-style: none;
}
.navds-dropdown__list-item {
margin: 0;
}
.navds-dropdown__list-heading {
margin: var(--a-spacing-1) var(--a-spacing-4) var(--a-spacing-3);
}
.navds-dropdown__item {
border: none;
margin: 0;
overflow: visible;
background: transparent;
color: var(--ac-dropdown-item-text, var(--a-text-action));
font: inherit;
text-decoration: none;
text-align: left;
cursor: pointer;
width: 100%;
display: flex;
align-items: center;
gap: var(--a-spacing-2);
padding: var(--a-spacing-1) var(--a-spacing-4);
}
.navds-dropdown__item:hover {
background-color: var(--ac-dropdown-item-hover-bg, var(--a-surface-action-subtle-hover));
}
.navds-dropdown__item:active {
background-color: var(--ac-dropdown-item-active-bg, var(--a-surface-action-active));
color: var(--ac-dropdown-item-active-text, var(--a-text-on-action));
}
.navds-dropdown__item:focus-visible {
outline: none;
box-shadow: inset 0 0 0 2px var(--a-border-focus);
}
@supports not selector(:focus-visible) {
.navds-dropdown__item:focus {
outline: none;
box-shadow: inset 0 0 0 2px var(--a-border-focus);
}
}
.navds-dropdown__item:disabled {
color: var(--ac-dropdown-item-text, var(--a-text-action));
opacity: 0.3;
background: transparent;
cursor: not-allowed;
}
.navds-internalheader {
display: flex;
align-self: stretch;
background: var(--ac-internalheader-bg, var(--a-surface-inverted));
min-height: var(--a-spacing-12);
--navds-internalheader-focus: inset 0 0 0 2px var(--a-border-focus-on-inverted);
}
.navds-internalheader__title {
border: none;
overflow: visible;
background: transparent;
font: inherit;
font-weight: var(--a-font-weight-bold);
line-height: normal;
text-align: left;
padding: 0 var(--a-spacing-5) 0 var(--a-spacing-6);
border-right: 1px solid var(--ac-internalheader-divider, var(--a-gray-600));
display: flex;
align-items: center;
text-decoration: none;
margin: 0;
color: var(--ac-internalheader-text, var(--a-text-on-inverted));
}
button.navds-internalheader__title {
cursor: pointer;
}
.navds-internalheader__user {
padding: 0 var(--a-spacing-5);
border-left: 1px solid var(--ac-internalheader-divider, var(--a-gray-600));
display: flex;
align-items: center;
}
.navds-internalheader__button {
border: none;
margin: 0;
padding: 0 var(--a-spacing-3);
overflow: visible;
background: transparent;
font: inherit;
line-height: normal;
cursor: pointer;
text-align: left;
display: flex;
align-items: center;
justify-self: center;
gap: var(--a-spacing-2);
border-left: 1px solid var(--ac-internalheader-divider, var(--a-gray-600));
color: var(--ac-internalheader-text, var(--a-text-on-inverted));
}
a.navds-internalheader__title:hover,
button.navds-internalheader__title:hover,
.navds-internalheader__button:hover {
background-color: var(--ac-internalheader-hover-bg, var(--a-surface-inverted-hover));
}
.navds-internalheader__title:focus-visible,
.navds-internalheader__button:focus-visible {
box-shadow: var(--navds-internalheader-focus);
outline: none;
}
@supports not selector(:focus-visible) {
.navds-internalheader__title:focus,
.navds-internalheader__button:focus {
box-shadow: var(--navds-internalheader-focus);
outline: none;
}
}
a.navds-internalheader__title:active,
button.navds-internalheader__title:active,
.navds-internalheader__button:active {
background-color: var(--ac-internalheader-active-bg, var(--a-surface-inverted-active));
}
.navds-internalheader__user-button {
padding-left: var(--a-spacing-5);
gap: var(--a-spacing-4);
}
.navds-timeline {
position: relative;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
width: 100%;
min-width: fit-content;
align-items: center;
}
.navds-timeline__axislabels {
position: relative;
height: 1rem;
box-sizing: content-box;
grid-column: 2;
}
.navds-timeline__row-label {
white-space: nowrap;
width: auto;
margin-right: var(--a-spacing-4);
grid-column: 1;
min-height: 1.5rem;
display: flex;
align-items: center;
gap: var(--a-spacing-2);
}
.navds-timeline__row-label:where(:nth-last-child(2)) {
align-self: flex-end;
}
.navds-timeline__axislabels-label {
position: absolute;
color: var(--ac-timeline-axislabel-text, var(--a-text-subtle));
white-space: nowrap;
}
.navds-timeline__row {
display: flex;
background: var(--ac-timeline-row-bg, var(--a-surface-subtle));
margin: var(--a-spacing-4) 0;
grid-column: 2;
}
.navds-timeline__row--active {
background: var(--ac-timeline-row-active-bg, var(--a-surface-selected));
}
.navds-timeline__row:last-of-type {
margin-bottom: 0;
}
.navds-timeline__row-periods {
min-height: 1.5rem;
position: relative;
width: 100%;
margin: 0;
}
.navds-timeline__row-periods > li {
list-style-type: none;
}
.navds-timeline__period {
height: 100%;
border-radius: var(--a-border-radius-full);
position: absolute;
padding: 0;
display: flex;
align-items: center;
z-index: 2;
border: none;
font-size: 1rem;
}
.navds-timeline__period--inner {
margin: 0 var(--a-spacing-1);
overflow: hidden;
white-space: nowrap;
text-overflow: clip;
text-align: left;
display: flex;
align-items: center;
}
.navds-timeline__period--inner svg {
flex-shrink: 0;
}
.navds-timeline__period--clickable {
cursor: pointer;
}
.navds-timeline__period--success {
background: var(--ac-timeline-period-success-bg, var(--a-surface-success-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-success-border, var(--a-border-success));
}
.navds-timeline__period--success.navds-timeline__period--clickable:hover {
background: var(--a-surface-success-subtle-hover);
background: var(--ac-timeline-period-success-bg-hover, var(--a-surface-success-subtle-hover));
}
.navds-timeline__period--warning {
background: var(--ac-timeline-period-warning-bg, var(--a-surface-warning-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-warning-border, var(--a-border-warning));
}
.navds-timeline__period--warning.navds-timeline__period--clickable:hover {
background: var(--ac-timeline-period-warning-bg-hover, var(--a-surface-warning-subtle-hover));
}
.navds-timeline__period--danger {
background: var(--ac-timeline-period-danger-bg, var(--a-surface-danger-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-danger-border, var(--a-border-danger));
}
.navds-timeline__period--danger.navds-timeline__period--clickable:hover {
background: var(--ac-timeline-period-danger-bg-hover, var(--a-surface-danger-subtle-hover));
}
.navds-timeline__period--info {
background: var(--ac-timeline-period-info-bg, var(--a-surface-info-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-info-border, var(--a-border-info));
}
.navds-timeline__period--info.navds-timeline__period--clickable:hover {
background: var(--ac-timeline-period-info-bg-hover, var(--a-surface-info-subtle-hover));
}
.navds-timeline__period--neutral {
background: var(--ac-timeline-period-neutral-bg, var(--a-bg-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-neutral-border, var(--a-border-default));
}
.navds-timeline__period--neutral.navds-timeline__period--clickable:hover {
background: var(--ac-timeline-period-neutral-bg-hover, var(--a-gray-200));
}
.navds-timeline__period--connected-both {
border-radius: 0;
}
.navds-timeline__period--connected-right {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
.navds-timeline__period--connected-left {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
.navds-timeline__period--selected {
box-shadow: inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected));
z-index: 3;
}
.navds-timeline__pin-wrapper {
position: absolute;
grid-column: 2;
top: 0;
z-index: 1;
height: 100%;
display: flex;
flex-direction: column-reverse;
isolation: isolate;
--navdsc-timeline-pin-size: 0.9rem;
}
.navds-timeline__pin-button {
border: none;
cursor: pointer;
background: var(--a-surface-default);
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 4px var(--ac-timeline-pin-bg, var(--a-surface-danger)), 0 0 0 5px var(--a-surface-default);
z-index: 2;
border-radius: var(--a-border-radius-full);
padding: 3.5px;
position: relative;
}
.navds-timeline__pin-button::before {
content: "";
inset: 0;
position: absolute;
width: 25px;
height: 25px;
border-radius: var(--a-border-radius-full);
left: calc(-12.5px + 3.5px);
top: calc(-12.5px + 3.5px);
}
.navds-timeline__pin-button:focus-visible {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 3px var(--ac-timeline-pin-bg, var(--a-surface-danger)), 0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
outline: none;
}
.navds-timeline__pin-button:hover {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 4px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)), 0 0 0 5px var(--a-surface-default);
}
.navds-timeline__pin-button:hover:focus-visible {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 3px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)), 0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
}
@supports not selector(:focus-visible) {
.navds-timeline__pin-button:focus {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 3px var(--ac-timeline-pin-bg, var(--a-surface-danger)), 0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
outline: none;
}
.navds-timeline__pin-button:hover:focus {
box-shadow: inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 3px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)), 0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
}
}
.navds-timeline__pin-wrapper::before {
content: "";
top: var(--navdsc-timeline-pin-size);
height: calc(94% - var(--navdsc-timeline-pin-size));
width: 1px;
margin: 0 auto;
background: var(--a-surface-inverted);
}
.navds-timeline__zoom {
margin-top: var(--a-spacing-6);
float: right;
display: flex;
list-style-type: none;
}
.navds-timeline__zoom-button {
all: unset;
cursor: pointer;
padding: 6px 9px 6px 8px;
border: 1px solid var(--ac-timeline-zoom-border, var(--a-border-default));
border-width: 1px 0 1px 1px;
background: var(--ac-timeline-zoom-bg, var(--a-surface-default));
}
.navds-timeline__zoom li:first-child .navds-timeline__zoom-button {
border-radius: var(--a-border-radius-medium) 0 0 var(--a-border-radius-medium);
}
.navds-timeline__zoom li:last-child .navds-timeline__zoom-button {
border-width: 1px;
border-radius: 0 var(--a-border-radius-medium) var(--a-border-radius-medium) 0;
}
.navds-timeline__zoom li:only-child .navds-timeline__zoom-button {
border-radius: var(--a-border-radius-medium);
}
.navds-timeline__zoom-button:not([aria-pressed="true"]):hover {
background: var(--ac-timeline-zoom-bg-hover, var(--a-surface-action-subtle-hover));
}
.navds-timeline__zoom-button[aria-pressed="true"] {
background: var(--ac-timeline-zoom-selected-bg, var(--a-surface-inverted));
color: var(--ac-timeline-zoom-selected-text, var(--a-text-on-inverted));
}
.navds-timeline__period:focus-visible {
outline: none;
z-index: 4;
box-shadow: 0 0 0 2px var(--a-border-focus);
}
.navds-timeline__period--selected:focus-visible {
box-shadow: inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected)),
0 0 0 2px var(--a-border-focus);
z-index: 3;
}
.navds-timeline__zoom li:focus-within {
z-index: var(--a-z-index-focus);
}
.navds-timeline__zoom-button:focus-visible {
box-shadow: 0 0 0 1px var(--a-surface-default), 0 0 0 3px var(--a-border-focus);
border-width: 1px;
}
.navds-timeline__zoom li:not(:last-child) .navds-timeline__zoom-button:focus-visible {
margin-right: 2px;
padding-right: 6px;
}
@supports not selector(:focus-visible) {
.navds-timeline__period:focus {
outline: none;
z-index: 4;
box-shadow: 0 0 0 2px var(--a-border-focus);
}
.navds-timeline__period--selected:focus {
box-shadow: inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected)),
0 0 0 2px var(--a-border-focus);
z-index: 3;
}
.navds-timeline__zoom-button:focus {
box-shadow: 0 0 0 1px var(--a-surface-default), 0 0 0 3px var(--a-border-focus);
border-width: 1px;
}
.navds-timeline__zoom li:not(:last-child) .navds-timeline__zoom-button:focus {
margin-right: 2px;
padding-right: 6px;
}
}
/**
* Timeline Popover
*/
.navds-timeline__popover {
z-index: var(--a-z-index-popover);
background-color: var(--ac-popover-bg, var(--a-surface-default));
box-shadow: var(--a-shadow-medium);
border: 1px solid;
border-color: var(--ac-popover-border, var(--a-border-default));
border-radius: var(--a-border-radius-medium);
}
.navds-timeline__popover:focus {
outline: none;
}
.navds-timeline__popover-content {
padding: var(--a-spacing-3);
}
.navds-timeline__popover-arrow {
position: absolute;
z-index: -1;
transform: rotate(45deg);
background-color: var(--ac-popover-bg, var(--a-surface-default));
border: 1px solid;
border-color: var(--ac-popover-border, var(--a-border-default));
width: 1rem;
height: 1rem;
}
.navds-timeline__popover[data-placement^="top"] > .navds-timeline__popover-arrow {
border-left-color: transparent;
border-top-color: transparent;
}
.navds-timeline__popover[data-placement^="bottom"] > .navds-timeline__popover-arrow {
border-bottom-color: transparent;
border-right-color: transparent;
}
.navds-timeline__popover[data-placement^="left"] > .navds-timeline__popover-arrow {
border-left-color: transparent;
border-bottom-color: transparent;
}
.navds-timeline__popover[data-placement^="right"] > .navds-timeline__popover-arrow {
border-right-color: transparent;
border-top-color: transparent;
}
.tokens {
--ac-internalheader-bg: red;
--ac-internalheader-active-bg: orange;
}
@@ -0,0 +1,17 @@
const StyledDiv = styled`
.navds-dropdown__menu {}
.navds-dropdown__divider {}
button.navds-internalheader__title:active {}
.navds-timeline__popover[data-placement^="left"] > .navds-timeline__popover-arrow {}
.navds-timeline__period--danger {}
`;
<style>
{`
.navds-dropdown__menu {}
.navds-dropdown__divider {}
button.navds-internalheader__title:active {}
.navds-timeline__popover[data-placement^="left"] > .navds-timeline__popover-arrow {}
.navds-timeline__period--danger {}
`}
</style>;
@@ -1,6 +1,6 @@
import { check } from "../../../../utils/check";
const migration = "update-js-tokens";
const migration = "internal-css";
const fixtures = ["complete"];
for (const fixture of fixtures) {
@@ -0,0 +1,38 @@
import { getLineTerminator } from "../../../utils/lineterminator";
import moveAndRenameImport from "../../../utils/moveAndRenameImport";
/**
* @param {import('jscodeshift').FileInfo} file
* @param {import('jscodeshift').API} api
*/
export default function transformer(file, api, options, ...rest) {
const j = api.jscodeshift;
let root: any;
try {
root = j(file.source);
} catch {
return file.source;
}
moveAndRenameImport(j, root, {
fromImport: "@navikt/ds-react-internal",
toImport: "@navikt/ds-react",
fromName: "Header",
toName: "InternalHeader",
});
moveAndRenameImport(j, root, {
fromImport: "@navikt/ds-react-internal",
toImport: "@navikt/ds-react",
fromName: "Dropdown",
toName: "Dropdown",
});
moveAndRenameImport(j, root, {
fromImport: "@navikt/ds-react-internal",
toImport: "@navikt/ds-react",
fromName: "Timeline",
toName: "Timeline",
});
return root.toSource(getLineTerminator(file.source));
}
@@ -0,0 +1,2 @@
import { Dropdown, Timeline, Header } from "@navikt/ds-react-internal";
import { Button, CopyButton } from "@navikt/ds-react";
@@ -0,0 +1,7 @@
import {
Button,
CopyButton,
InternalHeader as Header,
Dropdown,
Timeline,
} from "@navikt/ds-react";
@@ -0,0 +1,5 @@
import {
Dropdown as DSDropdown,
Timeline as DSTimeline,
Header as TestHeader,
} from "@navikt/ds-react-internal";
@@ -0,0 +1,5 @@
import {
InternalHeader as TestHeader,
Dropdown as DSDropdown,
Timeline as DSTimeline,
} from "@navikt/ds-react";
@@ -0,0 +1 @@
import { Header as InternalHeader } from "@navikt/ds-react-internal";
@@ -0,0 +1 @@
import { InternalHeader } from "@navikt/ds-react";
@@ -0,0 +1 @@
import { Dropdown, Timeline, Header } from "@navikt/ds-react-internal";
@@ -0,0 +1 @@
import { InternalHeader as Header, Dropdown, Timeline } from "@navikt/ds-react";
@@ -1,7 +1,7 @@
import { check } from "../../../../utils/check";
const migration = "update-css-tokens";
const fixtures = ["complete"];
const migration = "internal-react";
const fixtures = ["import", "import-add", "import-alias", "import-edgecase"];
for (const fixture of fixtures) {
check(__dirname, {
@@ -9,10 +9,4 @@ for (const fixture of fixtures) {
migration,
extension: "js",
});
check(__dirname, {
fixture,
migration,
extension: "css",
});
}
@@ -0,0 +1,3 @@
export const getLineTerminator = (source: string) => ({
lineTerminator: source.includes("\r\n") ? "\r\n" : "\n",
});
@@ -8,8 +8,16 @@ export default function moveAndRenameImport(
toImport,
fromName,
toName,
}: { fromImport: string; toImport: string; fromName: string; toName: string }
ignoreAlias = false,
}: {
fromImport: string;
toImport: string;
fromName: string;
toName: string;
ignoreAlias?: boolean;
}
) {
/* Does package-name exist */
const existingFromImport = root.find(j.ImportDeclaration, {
source: {
value: fromImport,
@@ -39,6 +47,7 @@ export default function moveAndRenameImport(
existingFromImportSpecifier.remove();
}
/* Remove import if its now empty */
if (
!existingFromImport.get("specifiers").value?.length ||
existingFromImport.get("specifiers").value?.length === 0
@@ -46,12 +55,14 @@ export default function moveAndRenameImport(
existingFromImport.remove();
}
/* Does package exist */
const existingImport = root.find(j.ImportDeclaration, {
source: {
value: toImport,
},
});
/* Check if migrated name allready exist */
const existingImportSpecifier = existingImport.find(j.ImportSpecifier, {
imported: {
name: toName,
@@ -59,7 +70,9 @@ export default function moveAndRenameImport(
});
if (existingImportSpecifier.length <= 0) {
const newImportSpecifier = j.importSpecifier(j.identifier(toName));
const newImportSpecifier = ignoreAlias
? j.importSpecifier(j.identifier(toName))
: j.importSpecifier(j.identifier(toName), j.identifier(localname));
if (existingImport.length > 0) {
existingImport.get("specifiers").push(newImportSpecifier);
-9
View File
@@ -1,9 +0,0 @@
*.d.ts
*.js
bin/*.js
*.js.map
!transforms/**/__testfixtures__/**/*.js
!transforms/**/tests/**/*.output.js
!transforms/**/tests/**/*.input.js
transforms/**/tests/**/*.test.js
!jest.config.js
-227
View File
@@ -1,227 +0,0 @@
# @navikt/ds-codemod
## 3.2.3
## 3.2.2
## 3.2.1
## 3.2.0
## 3.1.3
## 3.1.2
## 3.1.1
## 3.1.0
## 3.0.1
## 3.0.0
## 2.9.8
## 2.9.7
## 2.9.6
## 2.9.5
## 2.9.4
### Patch Changes
- [#1952](https://github.com/navikt/aksel/pull/1952) [`27b2b4a11`](https://github.com/navikt/aksel/commit/27b2b4a11caf5ca05c96c686c453653d8a900e5f) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :truck: Flyttet Codemods from `@navikt/ds-codemods` -> `@navikt/aksel`.
- `@navikt/ds-codemods` vil bli deprecated ettehvert.
## 2.9.3
## 2.9.2
## 2.9.1
## 2.9.0
## 2.8.16
## 2.8.15
### Patch Changes
- [#1930](https://github.com/navikt/aksel/pull/1930) [`6682be1c8`](https://github.com/navikt/aksel/commit/6682be1c8e6562213c64e5be4bed70fef54ab865) Thanks [@KenAJoh](https://github.com/KenAJoh)! - Alle pakker implementerer nå npm provenance (beta)
## 2.8.14
## 2.8.13
## 2.8.12
## 2.8.11
## 2.8.10
## 2.8.9
## 2.8.8
## 2.8.7
## 2.8.6
## 2.8.5
## 2.8.4
## 2.8.3
## 2.8.2
## 2.8.1
## 2.8.0
## 2.7.8
## 2.7.7
## 2.7.6
## 2.7.5
## 2.7.4
## 2.7.3
## 2.7.2
## 2.7.1
## 2.7.0
## 2.6.2
## 2.6.1
## 2.6.0
## 2.5.1
## 2.5.0
## 2.4.3
## 2.4.2
### Patch Changes
- [#1823](https://github.com/navikt/aksel/pull/1823) [`a7ce61f84`](https://github.com/navikt/aksel/commit/a7ce61f840e5bfaafc4f70e550167fe0095555b8) Thanks [@kschieren](https://github.com/kschieren)! - added support for nested lists
## 2.4.1
## 2.4.0
## 2.3.1
## 2.3.0
## 2.2.0
## 2.1.7
## 2.1.6
## 2.1.5
## 2.1.4
## 2.1.3
## 2.1.2
## 2.1.1
## 2.1.0
## 2.0.18
## 2.0.17
## 2.0.16
## 2.0.15
## 2.0.14
## 2.0.13
## 2.0.12
## 2.0.11
## 2.0.10
## 2.0.9
## 2.0.8
## 2.0.7
## 2.0.6
## 2.0.5
## 2.0.4
## 2.0.3
## 2.0.2
## 2.0.1
## 2.0.0
### Major Changes
- [`6b96e4833`](https://github.com/navikt/aksel/commit/6b96e48330c2e013a1acee85cefccd9ccc1aece4) Thanks [@KenAJoh](https://github.com/KenAJoh)! - v2: Tokens update and font-loading
## 1.5.10
## 1.5.9
## 1.5.8
## 1.5.7
## 1.5.6
## 1.5.5
## 1.5.4
## 1.5.3
## 1.5.2
## 1.5.1
## 1.5.0
## 1.4.4
## 1.4.3
## 1.4.2
## 1.4.1
## 1.4.0
## 1.3.39
### Patch Changes
- [`40f0b3340`](https://github.com/navikt/aksel/commit/40f0b3340d01bf85fecc04f2f3a8e8b2acf996f1) Thanks [@KenAJoh](https://github.com/KenAJoh)! - Bump for latest-tag
## 1.3.38
-4
View File
@@ -1,4 +0,0 @@
# Deperecation!
This package will be been deprecated in favor of [@navikt/aksel](...)
Run `npx @navikt/aksel codemod --help` to get started
-36
View File
@@ -1,36 +0,0 @@
import meow, { AnyFlags } from "meow";
import { migrate } from "./migrate";
import { cliConfig } from "./config";
const help = `
Usage
$ npx @navikt/ds-codemod ${cliConfig.args
.map((arg) => `<${arg.name}>`)
.join(" ")}
${cliConfig.args.map((arg) => `${arg.name}\t${arg.description}`).join("\n ")}
Options
${Object.entries(cliConfig.flags)
.map(([name, val]: [string, any]) => `--${name}\t${val.description}`)
.join("\n ")}
`;
const { input, flags } = meow({
description: cliConfig.description,
flags: Object.fromEntries(
Object.entries(cliConfig.flags).map(
([name, flag]: [string, any]): [string, AnyFlags] => [
name,
{
alias: flag.alias,
type: flag.type,
},
]
)
),
help,
});
export async function run() {
await migrate(input[0], input[1], flags);
}
-37
View File
@@ -1,37 +0,0 @@
const createCLIConfig = (config: any) => config;
export const cliConfig = createCLIConfig({
description: "Migrations for NAV designsystem solutions",
args: [
{
name: "migration",
description:
"One of the choices from https://github.com/navikt/aksel/blob/main/%40navikt/codemod/README.md",
},
{
name: "path",
description:
"Files or directory to transform. Can be a glob like src/**.css",
},
],
flags: {
dry: {
alias: "d",
description: "Dry run, no changes will be made to files",
type: "boolean",
},
print: {
alias: "p",
description: "Print transformed files",
type: "boolean",
},
force: {
alias: "f",
description: "Forcibly run migrations without checking git-changes",
type: "boolean",
},
},
});
export const DS_MIGRATION_COMMENT =
"ds-codemod: Unable to migrate the following expression. Please upgrade manually.";
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env node
const { run } = require("./cli");
run();
Loaded 100 of 1003 files, more files were not shown because too many files have changed in this diff. Show more